Tomcat启动流程

Posted fangke

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tomcat启动流程相关的知识,希望对你有一定的参考价值。

1. 首先去Tomcat的目录下载它的源码包

 

2. 把此项目解压之后,转换成maven的项目。创建pom.xml文件,以及创建home的目录,再把原先存在的conf目录和webapps目录拷贝至home目录下

 

 3. pom.xml加入必要的Tomcat的依赖

 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 4 
 5     <modelVersion>4.0.0</modelVersion>
 6     <packaging>war</packaging>
 7 
 8     <groupId>com.foreign</groupId>
 9     <artifactId>tomcat</artifactId>
10 
11     <name>Tomcat8.5</name>
12     <version>8.5</version>
13 
14     
15     <build>
16         <finalName>Tomcat8.5</finalName>
17         <sourceDirectory>java</sourceDirectory>
18         <resources>
19             <resource>
20                 <directory>java</directory>
21             </resource>
22         </resources>
23         <plugins>
24             <plugin>
25                 <groupId>org.apache.maven.plugins</groupId>
26                 <artifactId>maven-compiler-plugin</artifactId>
27                 <version>2.3</version>
28                 <configuration>
29                     <encoding>UTF-8</encoding>
30                     <source>1.8</source>
31                     <target>1.8</target>
32                 </configuration>
33             </plugin>
34         </plugins>
35     </build>
36     <dependencies>
37         <dependency>
38             <groupId>junit</groupId>
39             <artifactId>junit</artifactId>
40             <version>4.12</version>
41             <scope>test</scope>
42         </dependency>
43         <dependency>
44             <groupId>org.easymock</groupId>
45             <artifactId>easymock</artifactId>
46             <version>3.4</version>
47         </dependency>
48         <dependency>
49             <groupId>ant</groupId>
50             <artifactId>ant</artifactId>
51             <version>1.7.0</version>
52         </dependency>
53         <dependency>
54             <groupId>wsdl4j</groupId>
55             <artifactId>wsdl4j</artifactId>
56             <version>1.6.2</version>
57         </dependency>
58         <dependency>
59             <groupId>javax.xml</groupId>
60             <artifactId>jaxrpc</artifactId>
61             <version>1.1</version>
62         </dependency>
63         <dependency>
64             <groupId>org.eclipse.jdt.core.compiler</groupId>
65             <artifactId>ecj</artifactId>
66             <version>4.5.1</version>
67         </dependency>
68     </dependencies>
69 </project>

4. 在ContextConfig类下加入解析jsp的代码

 

  1 context.addServletContainerInitializer(new JasperInitializer(), null); 

5. 创建java的应用程序启动

 

 6. VM options

1 -Dcatalina.home=/Users/fangke/Documents/code-resource/tomcat/apache-tomcat-8.5.47-src/home 
2 -Dcatalina.base=/Users/fangke/Documents/code-resource/tomcat/apache-tomcat-8.5.47-src/home 
3 -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 
4 -Djava.util.logging.config.file=/Users/fangke/Documents/code-resource/tomcat/apache-tomcat-8.5.47-src/home/conf/logging.properties

7. 分析下tomcat的启动流程

8. 其实tomcat采用了模版方法的设计模式,把公共的方法init,start,destory,stop等方法抽取到了Lifecycle的接口中,这样就能确定执行流程

 

 9. Bootstrap类的main方法会创建一个init方法

 1 public static void main(String args[]) {
 2 
 3         if (daemon == null) {
 4             // Don\'t set daemon until init() has completed
 5             Bootstrap bootstrap = new Bootstrap();
 6             try {
 7                 bootstrap.init();
 8             } catch (Throwable t) {
 9                 handleThrowable(t);
10                 t.printStackTrace();
11                 return;
12             }
13             daemon = bootstrap;

10. 该方法会通过反射创建出一个Catalina的load方法

 1 public void init() throws Exception {
 2 
 3         initClassLoaders();
 4 
 5         Thread.currentThread().setContextClassLoader(catalinaLoader);
 6 
 7         SecurityClassLoad.securityClassLoad(catalinaLoader);
 8 
 9         // Load our startup class and call its process() method
10         if (log.isDebugEnabled())
11             log.debug("Loading startup class");
12         Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
13         Object startupInstance = startupClass.getConstructor().newInstance();
14 
15         // Set the shared extensions class loader
16         if (log.isDebugEnabled())
17             log.debug("Setting startup class properties");
18         String methodName = "setParentClassLoader";
19         Class<?> paramTypes[] = new Class[1];
20         paramTypes[0] = Class.forName("java.lang.ClassLoader");
21         Object paramValues[] = new Object[1];
22         paramValues[0] = sharedLoader;
23         Method method =
24             startupInstance.getClass().getMethod(methodName, paramTypes);
25         //通过反射调用catalina中的load方法
26         method.invoke(startupInstance, paramValues);
27 
28         catalinaDaemon = startupInstance;
29 
30     }

11. Catalina的load方法先去解析Tomcat的Server.xml配置文件,然后会去调用server的init方法

 1 public void load() {
 2 
 3         if (loaded) {
 4             return;
 5         }
 6         loaded = true;
 7 
 8         long t1 = System.nanoTime();
 9 
10         initDirs();
11 
12         // Before digester - it may be needed
13         initNaming();
14 
15         // Create and execute our Digester
16         //解析tomcat的xml文件
17         Digester digester = createStartDigester();
 1 // Start the new server
 2         try {
 3             //调用server的init方法
 4             getServer().init();
 5         } catch (LifecycleException e) {
 6             if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
 7                 throw new java.lang.Error(e);
 8             } else {
 9                 log.error("Catalina.start", e);
10             }
11         }

12. StanderServer里面会去调用多个service的init方法

1 // Initialize our defined Services
2         for (int i = 0; i < services.length; i++) {
3             //调用了N个service的init方法
4             services[i].init();
5         }

13. StanderService里面会分别去调用engine,executor,connector的init方法

 1 @Override
 2     protected void initInternal() throws LifecycleException {
 3 
 4         super.initInternal();
 5 
 6         if (engine != null) {
 7             //调用engine的init方法
 8             engine.init();
 9         }
10 
11         // Initialize any Executors
12         for (Executor executor : findExecutors()) {
13             if (executor instanceof JmxEnabled) {
14                 ((JmxEnabled) executor).setDomain(getDomain());
15             }
16             //调用executor的init方法
17             executor.init();
18         }
19 
20         // Initialize mapper listener
21         mapperListener.init();
22 
23         // Initialize our defined Connectors
24         synchronized (connectorsLock) {
25             for (Connector connector : connectors) {
26                 try {
27                     //调用connector的init方法
28                     connector.init();
29                 } catch (Exception e) {
30                     String message = sm.getString(
31                             "standardService.connector.initFailed", connector);
32                     log.error(message, e);
33 
34                     if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
35                         throw new LifecycleException(message);
36                 }
37             }
38         }
39     }

14. 直接到connector里面会去调用ProtocolHandler的init方法

1 try {
2             //调用protocolHandler的init方法
3             protocolHandler.init();
4         } catch (Exception e) {
5             throw new LifecycleException(
6                     sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
7         }

15. 会去调用endpoint的init方法

 1 public void init() throws Exception {
 2         if (getLog().isInfoEnabled()) {
 3             getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
 4         }
 5 
 6         if (oname == null) {
 7             // Component not pre-registered so register it
 8             oname = createObjectName();
 9             if (oname != null) {
10                 Registry.getRegistry(null, null).registerComponent(this, oname, null);
11             }
12         }
13 
14         if (this.domain != null) {
15             rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
16             Registry.getRegistry(null, null).registerComponent(
17                     getHandler().getGlobal(), rgOname, null);
18         }
19 
20         String endpointName = getName();
21         endpoint.setName(endpointName.substring(1, endpointName.length()-1));
22         endpoint.setDomain(domain);
23 
24         //调用了endpoint的init方法
25         endpoint.init();
26     }

16. endpoint里面的bind方法会去绑定8080 8089端口

1 @Override
2     public void bind() throws Exception {
3         //绑定监听的端口号InetSocketAddress
4         if (!getUseInheritedChannel()) {
5             serverSock = ServerSocketChannel.open();
6             socketProperties.setProperties(serverSock.socket());
7             InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
8             serverSock.socket().bind(addr,getAcceptCount());

17. 至此init方法走完,会回到Bootstrap方法执行start方法,以此顺序继续执行所有的start方法

1 public void start()
2         throws Exception {
3         if( catalinaDaemon==null ) init();
4 
5         Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
6         //通过反射调用catalina的start方法
7         method.invoke(catalinaDaemon, (Object [])null);
8 
9     }

 

以上是关于Tomcat启动流程的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat启动流程简析

二:Tomcat源码之整体架构与启动流程

springboot内置tomcat启动全流程详解及处理请求详解

Tomcat源码篇-启动核心流程-没你想的那么难哦

Tomcat源码解析-启动过程分析之主干流程

浅谈Tomcat的启动流程(源码级别)