http://blog.csdn.net/teabook00/article/details/5620023
下面先粗略的过下整个流程。
1, tomcat的启动是从Bootstrap开始, 下面是main()的主要代码
public static void main(String args[]) { if (daemon == null) { daemon = new Bootstrap(); try { daemon.init(); } catch (Throwable t) { t.printStackTrace(); return; } } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; daemon.load(args); daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); daemon.load(args); daemon.start(); } else if (command.equals("stop")) { daemon.stopServer(args); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { t.printStackTrace(); } }
通过反射的方式,分别调用Catalina的load()和start()的方法。
2, load方法主要完成组件的装配以及组件的初始化。 先看下面的load方法,
//因为需要调用多个方法,这里将load方法的主要代码合并到了一起
public void load() {
Digester digester = new Digester();
// Configure the actions we will be using
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
digester.addObjectCreate("Server/Service",
"org.apache.catalina.core.StandardService",
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service",
"addService",
"org.apache.catalina.Service");
digester.addRule("Server/Service/Connector",
new ConnectorCreateRule());
digester.addRule("Server/Service/Connector",
new SetAllPropertiesRule(new String[]{"executor"}));
digester.addSetNext("Server/Service/Connector",
"addConnector",
"org.apache.catalina.connector.Connector");
// Add RuleSets for nested elements
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
// When the 'engine' is found, set the parentClassLoader.
digester.addRule("Server/Service/Engine",
new SetParentClassLoaderRule(parentClassLoader));
digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));
try {
file = configFile(); //读取conf/server.xml
inputStream = new FileInputStream(file);
inputSource = new InputSource("file://" + file.getAbsolutePath());
} catch (Exception e) {
}
try {
inputSource.setByteStream(inputStream);
digester.parse(inputSource);
} catch (Exception e) {
return;
}
getServer().initialize();
}
tomcat使用SAX来解析conf/server.xml, 以Service为例,来了解tomcat如何完成组件的组装。
(1) 下面是server.xml的配置文件
<?xml version='1.0' encoding='utf-8'?> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <Listener className="org.apache.catalina.core.JasperListener" /> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <Engine name="Catalina" defaultHost="localhost"> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host> </Engine> </Service> </Server>
(2) Digester 继承 DefaultHandler,作为server.xml解析的handler,下面是startElment 和 endElement的主要代码
public void startElement(String namespaceURI, String localName, String qName, Attributes list) throws SAXException { // Fire "begin" events for all relevant rules List rules = getRules().match(namespaceURI, match); matches.push(rules); if ((rules != null) && (rules.size() > 0)) { for (int i = 0; i < rules.size(); i++) { Rule rule = (Rule) rules.get(i); rule.begin(namespaceURI, name, list); } } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { // Fire "body" events for all relevant rules List rules = (List) matches.pop(); if ((rules != null) && (rules.size() > 0)) { String bodyText = this.bodyText.toString(); for (int i = 0; i < rules.size(); i++) { Rule rule = (Rule) rules.get(i); rule.body(namespaceURI, name, bodyText); } } // Fire "end" events for all relevant rules in reverse order if (rules != null) { for (int i = 0; i < rules.size(); i++) { int j = (rules.size() - i) - 1; Rule rule = (Rule) rules.get(j); rule.end(namespaceURI, name); } } }
(2) 调用addObjectCreate的方法,创建了ObjectCreateRule,下面是ObjectCreateRule的方法,begin方法主要根据className来创建一个实例,即创建了StandardService
public void begin(Attributes attributes) throws Exception { // Identify the name of the class to instantiate String realClassName = className; if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) { realClassName = value; } } // Instantiate the new object and push it on the context stack Class clazz = digester.getClassLoader().loadClass(realClassName); Object instance = clazz.newInstance(); digester.push(instance); } public void end() throws Exception { Object top = digester.pop(); }
(3)调用addSetProperties方法,创建SetPropertiesRule,下面是SetPropertiesRule的begin方法,主要用来初始化参数(根据server.xml中的配置)
public void begin(Attributes attributes) throws Exception { // Populate the corresponding properties of the top object Object top = digester.peek(); for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } String value = attributes.getValue(i); IntrospectionUtils.setProperty(top, name, value) } }
(4) 调用setNextRule方法,创建SetNextRule,下面是SetNextRule的end方法
public void end() throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.peek(1); // Call the specified method IntrospectionUtils.callMethod1(parent, methodName, child, paramType, digester.getClassLoader()); }
其中,child为Service,parent为Server,methodName为addService,这样就完成了Server/Service的组装。
3, 调用getServer().initialize() 方法初始化StandardServer对象,下面是StandardServer的initialize方法
public void initialize() throws LifecycleException { if (initialized) { log.info(sm.getString("standardServer.initialize.initialized")); return; } lifecycle.fireLifecycleEvent(INIT_EVENT, null); initialized = true; if( oname==null ) { try { oname=new ObjectName( "Catalina:type=Server"); Registry.getRegistry(null, null) .registerComponent(this, oname, null ); } catch (Exception e) { log.error("Error registering ",e); } } // Register global String cache try { ObjectName oname2 = new ObjectName(oname.getDomain() + ":type=StringCache"); Registry.getRegistry(null, null) .registerComponent(new StringCache(), oname2, null ); } catch (Exception e) { log.error("Error registering ",e); } // Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].initialize(); } }使用JMX管理Server对象,然后调用Service的initialize方法。后面StandardEngine, Connector等的初始化方法都相似。
4, 调用Catalina的start方法,主要代码如下
// Start the new server
if (getServer() instanceof Lifecycle) {
try {
((Lifecycle) getServer()).start();
} catch (LifecycleException e) {
log.error("Catalina.start: ", e);
}
}
5,调用StandardServer的start方法,主要代码如下
public void start() throws LifecycleException {
// Validate and update our current component state
if (started) {
log.debug(sm.getString("standardServer.start.started"));
return;
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our defined Services
synchronized (services) {
for (int i = 0; i < services.length; i++) {
if (services[i] instanceof Lifecycle)
((Lifecycle) services[i]).start();
}
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
6, 调用StandardService的start方法,代码如下
public void start() throws LifecycleException { // Validate and update our current component state if (started) { return; } if( ! initialized ) init(); lifecycle.fireLifecycleEvent(START_EVENT, null); started = true; // Start our defined Container first if (container != null) { synchronized (container) { if (container instanceof Lifecycle) { ((Lifecycle) container).start(); } } } synchronized (executors) { for ( int i=0; i<executors.size(); i++ ) { executors.get(i).start(); } } // Start our defined Connectors second synchronized (connectors) { for (int i = 0; i < connectors.length; i++) { try { ((Lifecycle) connectors[i]).start(); } catch (Exception e) { log.error(sm.getString( "standardService.connector.startFailed", connectors[i]), e); } } } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); }7, 调用StandardEngine的start方法,主要代码如下
public void start() throws LifecycleException { if( started ) { return; } if( !initialized ) { init(); } // Standard container startup super.start(); }StandardEngine继承ContainerBase,下面是ContainerBase的start方法
public synchronized void start() throws LifecycleException {
// Validate and update our current component state
if (started) {
return;
}
started = true;
// Start our subordinate components, if any
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any //StandardHost
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Start our thread
threadStart();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
在前面的组件装配过程中,通过digester.addSetNext("Server/Service/Engine/Host", "addChild", "org.apache.catalina.Container") 方法,将StandardHost与StandardEngine组装。因此findChildren得到StandardHost对象,执行其start方法。
8, 调用StandardHost的start方法,代码如下
public synchronized void start() throws LifecycleException { if( started ) { return; } if( ! initialized ) init(); // Set error report valve if ((errorReportValveClass != null) && (!errorReportValveClass.equals(""))) { try { boolean found = false; if(errorReportValveObjectName != null) { ObjectName[] names = ((StandardPipeline)pipeline).getValveObjectNames(); for (int i=0; !found && i<names.length; i++) if(errorReportValveObjectName.equals(names[i])) found = true ; } if(!found) { Valve valve = (Valve) Class.forName(errorReportValveClass) .newInstance(); addValve(valve); errorReportValveObjectName = ((ValveBase)valve).getObjectName() ; } } catch (Throwable t) { } } super.start(); }同样,StandardHost继承ContainerBase(代码见上面的ContainerBase),在调用lifecycle.fireLifecycleEvent(START_EVENT, null)时,会调用先前注册的LifecycleListener, 注册方法在前面的组装过程中,代码如下
digester.addRule(prefix + "Host", new LifecycleListenerRule ("org.apache.catalina.startup.HostConfig", "hostConfigClass"));
9, 调用HostConfig的lifecycleEvent方法
// Identify the host we are associated with try { host = (Host) event.getLifecycle(); if (host instanceof StandardHost) { setDeployXML(((StandardHost) host).isDeployXML()); setUnpackWARs(((StandardHost) host).isUnpackWARs()); setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware()); setXmlValidation(((StandardHost) host).getXmlValidation()); } } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.START_EVENT)) start(); else if (event.getType().equals(Lifecycle.STOP_EVENT)) stop();在start方法中,会调用deployApps方法,具体如下
protected void deployApps() { File appBase = appBase(); File configBase = configBase(); String[] filteredAppPaths = filterAppPaths(appBase.list()); // Deploy XML descriptors from configBase deployDescriptors(configBase, configBase.list()); // Deploy WARs, and loop if additional descriptors are found deployWARs(appBase, filteredAppPaths); // Deploy expanded folders deployDirectories(appBase, filteredAppPaths); }
10, 调用deployDescriptor方法,代码如下
protected void deployDescriptor(String contextPath, File contextXml, String file) { if (deploymentExists(contextPath)) { return; } DeployedApplication deployedApp = new DeployedApplication(contextPath); Context context = null; try { synchronized (digester) { try { context = (Context) digester.parse(contextXml); if (context == null) { log.error(sm.getString("hostConfig.deployDescriptor.error", file)); return; } } finally { digester.reset(); } } if (context instanceof Lifecycle) { Class clazz = Class.forName(host.getConfigClass()); LifecycleListener listener = (LifecycleListener) clazz.newInstance(); ((Lifecycle) context).addLifecycleListener(listener); } context.setConfigFile(contextXml.getAbsolutePath()); context.setPath(contextPath); host.addChild(context); ... }
11, StandardHost的addChild方法会调用addChildInternal,代码如下
private void addChildInternal(Container child) {
synchronized(children) {
if (children.get(child.getName()) != null)
throw new IllegalArgumentException("addChild: Child name '" +
child.getName() +
"' is not unique");
child.setParent(this); // May throw IAE
children.put(child.getName(), child);
// Start child
if (started && startChildren && (child instanceof Lifecycle)) {
boolean success = false;
try {
((Lifecycle) child).start();
success = true;
} catch (LifecycleException e) {
log.error("ContainerBase.addChild: start: ", e);
throw new IllegalStateException
("ContainerBase.addChild: start: " + e);
} finally {
if (!success) {
children.remove(child.getName());
}
}
}
fireContainerEvent(ADD_CHILD_EVENT, child);
}
}
由第十步可知,方法的参数为StandardContext对象,因此,会调用StandardContext的start方法。
12,调用StandardContext的start方法
public synchronized void start() throws LifecycleException {
....
try {
if (ok) {
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic),
// if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
}
}
....
}
在调用lifecycle.fireLifecycleEvent(START_EVENT, null)时,会调用先前注册的LifecycleListener, 注册方法在前面的组装过程中,代码如下
digester.addRule(prefix + "Context", new LifecycleListenerRule ("org.apache.catalina.startup.ContextConfig", "configClass"));
相关推荐
Tomcat启动流程.vsdx
详细说明了tomcat启动过程中 加载资源的顺序
介紹Tomcat5启动流程与配置详解,適合初學者。
tomcat启动流程图,我花了几个小时的时间生成的,对学习tomcat源码很有帮助,这是粒度最小的一张图,如果想要粗粒度的可以私信联系我。
之前tomcat启动老是报错,虽然不影响项目的启动运行,但是有强迫症的程序员会心里不爽: 如下: 问题分析 由于本机安装的jdk版本与tomcat中使用的jdk版本不一致导致的。 解决方法 后面我把原先tomcat启动环境用的...
详细讲解Tomcat启动的过程,了解tomcat原理
Tomcat启动流程分析 组件的生命周期管理 用Lifecycle管理启动、停止、关闭 Lifecycle接口预览 几个核心方法 Server中的init方法示例 为啥StandardServer没有init方法 LifecycleBase中的init与...
Tomcat初始化流程分析,Tomcat启动流程分析 Tomcat处理一次请求过程分析 servlet初始化流程
文档中描述了tomcat不能启动的个中问题,帮你解决tomcat配置过程中出现的问题.
SpringBoot-2.7.6内置Tomcat启动以及DispatcherServlet装配过程,源码跟踪调试流程图
主要介绍了springboot 基于Tomcat容器的自启动流程分析,Spring通过注解导入Bean大体可分为四种方式,我们主要来说Import的两种实现方法,需要的朋友可以参考下
这份Tomcat源码解析文档详细地介绍了Tomcat从启动到最后结束的过程,包括其中涉及的类和方法的调用过程。这份文档对于想要深入研究Java底层源码启动过程的人来说十分有用。除了介绍Tomcat的启动过程,这份文档还可以...
主要是讲解TOMCAT的系统框架, 以及启动流程。
对于tomcat的启动流程分析,从主流程Bootstrap -> Catalina -> Server -> service -> engine,connector;和分流程1.engine->host->context->wrapper ;2.connector -> ProtocolHandler->Endpoint;之中的方法调用进行...
Web应用程序在Tomcat启动前就安装好 • 动态的; 使用Tomcat Manager这个Web应用程序或者操纵已经部署的Web应用程序 Tomcat Manager 是一款工具它提供基于以URL为基础的Web应用程序部署特性。也有一种工具被称为...
1. Tomcat 启动过程分析。分析tomcat的启动过程 2. Tomcat Web容器功能分析。分析web容器的实现方法 3. Tomcat 其他配置说明。一些我们目前应用较少的Tomcat配置项说明
使用默认配置的tomcat,另外虚拟目录也可这设置: <Context path="/test" docBase="webContent" reloadable="true"/> 因为默认情况下,tomcat启动过程中配置虚拟目录的时候会从 webapps目录下查找webContent应用....
3-8Tomcat请求容器中的处理与启动过程源码实现(1).mp4
将tomcat加入到本地服务中去,设置tomcat的服务自动启动,这样在服务器上通过tomcat运行的项目,即使服务器重启,tomcat也可以自动重启,这样,项目也就不会宕机了。
介绍了关于tomcat5启动流程、配置详解及杂谈。