• 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     }
  • 相关阅读:
    针式电子书下载列表(暂时)
    硬盘坏道造成SQL 2000的异常
    一种“您无权查看该网页”的原因和解决方法
    学习英语的一些方法
    “针式背单词”帮助文件
    ClickOnce的Excel模板文件发布
    IC 设计书籍和相关资料
    Useful links on GPU Programming &Examp; Architecture
    点评美国名校的(EE)和(CS)
    微电子/物理学名人 约翰·巴丁 John Bardeen
  • 原文地址:https://www.cnblogs.com/fangke/p/11764929.html
Copyright © 2020-2023  润新知