根据Tomcat源码来看一下Tomcat启动过程都做了什么

部分代码为主要流程代码,删去了try-catch以及一些校验逻辑,方便理解主流程

先来一张启动过程时序图,了解一下启动顺序

Tomcat启动的入口类:org.apache.catalina.startup.Bootstrap#main

main方法是整个tomcat启动时的入口。在main方法中,使用bootstrap.init()来初始化类加载器和创建Catalina实例,然后再启动Catalina线程。

1 public static voidmain(String args[]) {2
3     if (daemon == null) {4         //Don't set daemon until init() has completed
5         Bootstrap bootstrap = newBootstrap();6         try{7 bootstrap.init();8         } catch(Throwable t) {9 handleThrowable(t);10 t.printStackTrace();11             return;12 }13         daemon =bootstrap;14     } else{15         //When running as a service the call to stop will be on a new16         //thread so make sure the correct class loader is used to prevent17         //a range of class not found exceptions.
18 Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);19 }20
21     try{22         String command = "start";23         if (args.length > 0) {24             command = args[args.length - 1];25 }26
27         if (command.equals("startd")) {28             args[args.length - 1] = "start";29 daemon.load(args);30 daemon.start();31         } else if (command.equals("stopd")) {32             args[args.length - 1] = "stop";33 daemon.stop();34         } else if (command.equals("start")) {35             daemon.setAwait(true);36 daemon.load(args);37 daemon.start();38         } else if (command.equals("stop")) {39 daemon.stopServer(args);40         } else if (command.equals("configtest")) {41 daemon.load(args);42             if (null==daemon.getServer()) {43                 System.exit(1);44 }45             System.exit(0);46         } else{47             log.warn("Bootstrap: command \"" + command + "\" does not exist.");48 }49     } catch(Throwable t) {50         //Unwrap the Exception for clearer error reporting
51         if (t instanceof InvocationTargetException &&
52                 t.getCause() != null) {53             t =t.getCause();54 }55 handleThrowable(t);56 t.printStackTrace();57         System.exit(1);58 }59
60 }

bootstrap.init()方法,用于初始化容器相关,首先创建类加载器,然后通过反射创建org.apache.catalina.startup.Catalina实例:

1 public void init() throwsException {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 =
13 catalinaLoader.loadClass14         ("org.apache.catalina.startup.Catalina");15     Object startupInstance =startupClass.newInstance();16
17     //Set the shared extensions class loader
18     if(log.isDebugEnabled())19         log.debug("Setting startup class properties");20     String methodName = "setParentClassLoader";21     Class<?> paramTypes[] = new Class[1];22     paramTypes[0] = Class.forName("java.lang.ClassLoader");23     Object paramValues[] = new Object[1];24     paramValues[0] =sharedLoader;25     Method method =
26 startupInstance.getClass().getMethod(methodName, paramTypes);27 method.invoke(startupInstance, paramValues);28
29     catalinaDaemon =startupInstance;30
31 }

之后Bootstrap的demon.start()方法就会调用Catalina的start方法。

Catalina实例执行start方法。这里有两个点,一个是load()加载server.xml配置、初始化Server的过程,一个是getServer().start()开启服务、初始化并开启一系列组件、子容器的过程。

org.apache.catalina.startup.Catalina#start
1 public voidstart() {2
3     if (getServer() == null) {4 load();5 }6
7     if (getServer() == null) {8         log.fatal("Cannot start server. Server instance is not configured.");9         return;10 }11
12     long t1 =System.nanoTime();13
14     //Start the new server
15     try{16 getServer().start();17     } catch(LifecycleException e) {18         log.fatal(sm.getString("catalina.serverStartFail"), e);19         try{20 getServer().destroy();21         } catch(LifecycleException e1) {22             log.debug("destroy() failed for failed Server ", e1);23 }24         return;25 }26
27     long t2 =System.nanoTime();28     if(log.isInfoEnabled()) {29         log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");30 }31
32     //Register shutdown hook
33     if(useShutdownHook) {34         if (shutdownHook == null) {35             shutdownHook = newCatalinaShutdownHook();36 }37 Runtime.getRuntime().addShutdownHook(shutdownHook);38
39         //If JULI is being used, disable JULI's shutdown hook since40         //shutdown hooks run in parallel and log messages may be lost41         //if JULI's hook completes before the CatalinaShutdownHook()
42         LogManager logManager =LogManager.getLogManager();43         if (logManager instanceofClassLoaderLogManager) {44 ((ClassLoaderLogManager) logManager).setUseShutdownHook(45                     false);46 }47 }48
49     if(await) {50 await();51 stop();52 }53 }

load方法解析server.xml配置文件,并加载Server、Service、Connector、Container、Engine、Host、Context、Wrapper一系列的容器。加载完成后,调用getServer().start()来开启一个新的Server。

下面先看load方法怎么加载组件和容器的:

1 /**
2 * Start a new server instance.3   */
4  public voidload() {5
6      long t1 =System.nanoTime();7
8 initDirs();9
10      //Before digester - it may be needed
11 initNaming();12
13      //Create and execute our Digester
14      Digester digester =createStartDigester();15
16      InputSource inputSource = null;17      InputStream inputStream = null;18      File file = null;19      file =configFile();20      inputStream = newFileInputStream(file);21      inputSource = newInputSource(file.toURI().toURL().toString());22 inputSource.setByteStream(inputStream);23      digester.push(this);24 digester.parse(inputSource);25
26
27      getServer().setCatalina(this);28 getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());29 getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());30
31      //Stream redirection
32 initStreams();33
34      //Start the new server
35 getServer().init();36  }

首先利用Digester类解析server.xml文件,得到容器的配置,并创建相应的对象,并关联父子容器。依次创建的是StandardServer、StandardService、StandardEngine、StandardHost。

然后拿到StandardServer实例调用init()方法初始化Tomcat容器的一系列组件。一些容器初始化的的时候,都会调用其子容器的init()方法,初始化它的子容器。顺序是StandardServer、StandardService、StandardEngine、Connector。每个容器都在初始化自身相关设置的同时,将子容器初始化。

这里插入一个Tomcat中生命周期的概念。在初始化、开启一系列组件、容器的过程中,由tomcat'管理的组件和容器,都有一个共同的特点,都实现了org.apache.catalina.Lifecycle接口,由Tomcat管理其生命周期。Lifecycle提供一种统一的管理对象生命周期的接口。通过Lifecycle、LifecycleListener、LifecycleEvent,Catalina实现了对tomcat各种组件、容器统一的启动和停止的方式。

在Tomcat服务开启过程中启动的一些列组件、容器,都继承了org.apache.catalina.util.LifecycleBase这个抽象类,其中的init()、start() 方法、stop() 方法,为其子类实现了统一的start和stop管理。方法中具体的initInternal()、startInternal() 和stopInternal() 方法,交由子类自己实现。

看一下LifecycleBase的init()和start()的实现吧:

org.apache.catalina.util.LifecycleBase#start
1 public final synchronized void init() throwsLifecycleException {2     if (!state.equals(LifecycleState.NEW)) {3 invalidTransition(Lifecycle.BEFORE_INIT_EVENT);4 }5
6     try{7         setStateInternal(LifecycleState.INITIALIZING, null, false);8 initInternal();9         setStateInternal(LifecycleState.INITIALIZED, null, false);10     } catch(Throwable t) {11 ExceptionUtils.handleThrowable(t);12         setStateInternal(LifecycleState.FAILED, null, false);13         throw newLifecycleException(14                 sm.getString("lifecycleBase.initFail",toString()), t);15 }16 }17
18
19 public final synchronized void start() throwsLifecycleException {20
21     if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
22 LifecycleState.STARTED.equals(state)) {23
24         if(log.isDebugEnabled()) {25             Exception e = newLifecycleException();26             log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);27         } else if(log.isInfoEnabled()) {28             log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));29 }30
31         return;32 }33
34     if(state.equals(LifecycleState.NEW)) {35 init();36     } else if(state.equals(LifecycleState.FAILED)) {37 stop();38     } else if (!state.equals(LifecycleState.INITIALIZED) &&
39             !state.equals(LifecycleState.STOPPED)) {40 invalidTransition(Lifecycle.BEFORE_START_EVENT);41 }42
43     try{44         setStateInternal(LifecycleState.STARTING_PREP, null, false);45 startInternal();46         if(state.equals(LifecycleState.FAILED)) {47 stop();48         } else if (!state.equals(LifecycleState.STARTING)) {49 invalidTransition(Lifecycle.AFTER_START_EVENT);50         } else{51             setStateInternal(LifecycleState.STARTED, null, false);52 }53     } catch(Throwable t) {54 ExceptionUtils.handleThrowable(t);55         setStateInternal(LifecycleState.FAILED, null, false);56         throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);57 }58 }

可以看到,init()和start()方法里,调用了initInternal()方法、startInternal()方法和stop()方法,这三者最终会走子类的具体实现。

上面的StandardServer的初始化过程就是一个活生生的例子。在Catalina的load过程中,getServer().init()方法就是LifecycleBase中的init()方法,调用initInternal()时是走的StandardServer的实现,StandardServer的initInternal()中会调用StandardServer的init()方法,进行子容器的初始化。然后依次初始化。

看一下代码,了解一下StandardServer中的initInternal()实现。

1 /**
2 * Invoke a pre-startup initialization. This is used to allow connectors3 * to bind to restricted ports under Unix operating environments.4  */
5 @Override6 protected void initInternal() throwsLifecycleException {7
8     super.initInternal();9
10     //Register global String cache11     //Note although the cache is global, if there are multiple Servers12     //present in the JVM (may happen when embedding) then the same cache13     //will be registered under multiple names
14     onameStringCache = register(new StringCache(), "type=StringCache");15
16     //Register the MBeanFactory
17     MBeanFactory factory = newMBeanFactory();18     factory.setContainer(this);19     onameMBeanFactory = register(factory, "type=MBeanFactory");20
21     //Register the naming resources
22 globalNamingResources.init();23
24     //Populate the extension validator with JARs from common and shared25     //class loaders
26     if (getCatalina() != null) {27         ClassLoader cl =getCatalina().getParentClassLoader();28         //Walk the class loader hierarchy. Stop at the system class loader.29         //This will add the shared (if present) and common class loaders
30         while (cl != null && cl !=ClassLoader.getSystemClassLoader()) {31             if (cl instanceofURLClassLoader) {32                 URL[] urls =((URLClassLoader) cl).getURLs();33                 for(URL url : urls) {34                     if (url.getProtocol().equals("file")) {35                         try{36                             File f = newFile (url.toURI());37                             if (f.isFile() &&
38                                     f.getName().endsWith(".jar")) {39 ExtensionValidator.addSystemResource(f);40 }41                         } catch(URISyntaxException e) {42                             //Ignore
43                         } catch(IOException e) {44                             //Ignore
45 }46 }47 }48 }49             cl =cl.getParent();50 }51 }52     //Initialize our defined Services
53     for (int i = 0; i < services.length; i++) {54 services[i].init();55 }56 }

再举一个具体的例子:

回到刚才的启动过程中,getServer().start()开启服务的方法,实际就是上面提到的LifecycleBase中的start()方法。其中,会调用org.apache.catalina.core.StandardServer#initInternal方法,初始化Server并调用Service的init方法。org.apache.catalina.core.StandardServer在其实现的startInternal() 中,开启naming resources和services,调用service的start方法,开启所有service,调用其service的startInternal()方法。

下面看一下StandardServer中的startInternal()的实现:

org.apache.catalina.core.StandardServer#startInternal
1 protected void startInternal() throwsLifecycleException {2
3     fireLifecycleEvent(CONFIGURE_START_EVENT, null);4 setState(LifecycleState.STARTING);5
6 globalNamingResources.start();7
8     //Start our defined Services
9     synchronized(servicesLock) {10         for (int i = 0; i < services.length; i++) {11 services[i].start();12 }13 }14 }

这里的service,是org.apache.catalina.core.StandardService的实例。

总结一下启动的Tomcat启动的过程

在Catalina的load方法里,就已经调用了StandardServer里的init方法,一层一层初始化了globalNamingResources,StandardService--》StandardEngine,executors,MapperListener,Connector--》CoyoteAdapter,protocolHandler。至此就将tomcat的catalina中的组件、容器初始化完成。 接下来就是调用start方法一层一层开启,StandardServer的startInternal方法,按层次start:globalNamingResources,StandardService--》StandardEngine,executors,MapperListener,Connector--》StandardHost,StandardContext,protocolHandler。顺序基本同init过程。StandardEngine在start时,会init子容器,并调用子容器的start方法。子容器依次这样init、start,就开启了StandardHost和StandardContext。

参考文章:

tomcat源码分析-Connector初始化与启动

tomcat源码分析-Container初始化与加载

tomcat源码分析-http请求在Container中的执行路线

tomcat源码解析(一)--启动与Server.xml文件的解析

转载于:https://www.cnblogs.com/z941030/p/8524882.html

Tomcat启动过程源码解读相关推荐

  1. Tomcat启动过程源码分析六

    前言 上一篇文章中我们讨论了Catalina类中start方法中一部分,今天这篇文章我们把Catalina类的start方法剩余部分讲解完毕,在讲解代码之前我们先看之前的一篇关于ShutdownHoo ...

  2. Tomcat启动过程源码分析四

    前言 上一篇文章中我们讨论了Bootstrap类中main方法中涉及到的init方法,今天这篇文章我们来查看下load方法. daemon.setAwait(true); daemon.load(ar ...

  3. Tomcat - Tomcat 8.5.55 启动过程源码分析阶段三_start阶段

    文章目录 启动流程分析 Pre Star阶段 start总览 start源码分析 StandardServer Start StandardService Start StandardEngine S ...

  4. Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化

    文章目录 启动流程分析 Pre load 加载初始化 总体预览 源码解析 load() Server初始化 Service初始化 Engine初始化 Connector 初始化 小结 启动流程分析 P ...

  5. SpringBoot2 | SpringBoot启动流程源码分析(一)

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 SpringBoot2 | SpringBoot启动流程源码分析(一) 置顶 张书康 201 ...

  6. Android系统默认Home应用程序(Launcher)的启动过程源码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还须要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  7. Activity启动流程源码分析-浅析生命周期函数

    源码分析 接着上一篇 Activity启动流程源码分析-setContentView源码阅读 的讲解,本节介绍一下Activity的生命周期函数何时被调用 要看Activity的生命周期函数何时被调用 ...

  8. Doris FE启动流程源码详细解析

    Doris FE启动流程源码详细解析 一.简介 Apache Doris是一个现代化的MPP分析型数据库产品.仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析.Apache Doris的分布 ...

  9. Android音频框架之二 用户录音启动流程源码走读

    前言 此篇是对<Android音频框架之一 详解audioPolicy流程及HAL驱动加载>的延续,此系列博文是记录在Android7.1系统即以后版本实现 内录音功能. 当用户使用 Au ...

最新文章

  1. JavaScript 计算两个颜色叠加值
  2. linux vsftp的配置
  3. 如何禁用文本选择突出显示
  4. 条件、循环、函数定义 练习(2017.9.12)
  5. ansible笔记(5):常用模块之文件操作(二)
  6. Android面试收集录4 Fragment详解
  7. python可以连接sql server_python连接sqlserver数据库
  8. java中解释命令_闲来无事可来了解下Java中Javadoc命令的用法
  9. SpringCloud工作笔记064---intellij idea 如何将一个普通项目转换为maven项目
  10. Qt4_写TCP客户/服务器应用程序
  11. win10用不了php_WIN10用不了
  12. 会员制营销系统_想提升门店经营水平?会员制营销法可以帮到你
  13. python 链表操作 优化_Python:如何修改列表时内存的使用和优化?
  14. 人脸检测进阶:更快的5点面部标志检测器
  15. matlab统计颗粒数,一种基于Matlab的谷物颗粒计数方法
  16. 微积分基本公式-牛顿莱布尼兹公式
  17. hdu 4747(区间更新)
  18. 多层交换机静态路由实验
  19. 组织行为学笔记(4)——人格与价值观
  20. 如何用CSS动画特效让图片旋转起来

热门文章

  1. 修改PHP上传文件的大小限制
  2. flash遨游缓存问题
  3. Silverlight教程第二部分:使用布局管理 (木野狐译)
  4. 隐式类型转换中显式申明的非必要性
  5. 两个小程序大概的了解一下java的线程
  6. linux shell中的eval命令
  7. Oracle创建、删除、备份表
  8. Android模糊查询excel文件内容,【excel】模糊查询关键字
  9. java的reentrantlock_JAVA中ReentrantLock详解(转)
  10. matlab自带的人脸分类器,基于MATLAB,运用PCA+SVM的特征脸方法人脸识别