美文网首页Tomcat
Tomcat之启动过程源码分析

Tomcat之启动过程源码分析

作者: loveFXX | 来源:发表于2020-05-24 15:41 被阅读0次

    LifecycleBase生命周期抽象类

    在分析启动流程之前,有必要对于实现了LifecycleBase这个类的所有类进行分析。结论是只要调用生命周期方法,都会先调用这个LifecycleBase的父类方法。以StandardServer和StandardEngine容器类为例

    1、StandardServer

    在具体分析之前需要看下StandardServer的继承关系图


    image.png

    StandardServer继承了生命周期抽象类LifecycleMBeanBase,LifecycleMBeanBase继承了LifecycleBase抽象类。由于StandardServer没有init、start、stop、destroy等方法,所以会到父类寻找这些方法。


    image.png
    ①、init
    org.apache.catalina.util.LifecycleBase#init
    image.png

    调用setStateInternal方法
    发布LifecycleState.INITIALIZING是before_init的生命周期事件
    ②、setStateInternal
    org.apache.catalina.util.LifecycleBase#setStateInternal


    image.png
    image.png
    image.png
    这个方法最重要的实现逻辑就是发布当前事件
    ③、fireLifecycleEvent
    org.apache.catalina.util.LifecycleBase#fireLifecycleEvent
    image.png
    根据传入类型type = "before_init"获取当前事件,然后调用当前容器包含的LifecycleListener的lifecycleEvent方法。
    ④、initInternal

    initInternal方法会调用到当前容器的initInternal方法。


    image.png
    2、StandardEngine继承图

    继承了ContainerBase,ContainerBase继承了LifecycleMBeanBase并实现了Container。
    LifecycleMBeanBase继承了LifecycleBase抽象类。


    image.png

    ①、start
    org.apache.catalina.util.LifecycleBase#start


    image.png
    发布LifecycleState.STARTING_PREP是before_start事件
    image.png
    ②、startInternal

    然后调用startInternal方法


    image.png
    Lifecycle有哪些LifecycleState事件

    before_init、after_init、start、before_start、after_start、stop、before_stop、after_stop、after_destroy、before_destroy、periodic、configure_start、configure_stop
    所以,任何容器类StandardService、StandardEngine、StandardHost、StandardContext、StandardWrapper及其他实现了LifecycleBase调用生命周期方法都是这样的调用流程

    Bootstrap启动Tomcat

    Tomcat启动通过Bootstrap类main方法启动


    image.png

    org.apache.catalina.startup.Bootstrap#main


    image.png
    image.png
    main方法主要步骤有三步:

    ①、init()
    ②、load()
    ③、start()

    1、init

    org.apache.catalina.startup.Bootstrap#init()


    image.png

    ①、初始化类加载器
    org.apache.catalina.startup.Bootstrap#initClassLoaders


    image.png
    commonLoader、catalinaLoader、sharedLoader类加载器都是URLClassLoader
    当前线程设置类加载器catalinaLoader
    image.png

    ②、启动类加载并创建实例对象Catalina
    设置Catalina类的父加载器setParentClassLoader是URLClassLoader


    image.png

    setAwait

    catalina设置Await是阻塞,true表示阻塞


    image.png

    2、load

    org.apache.catalina.startup.Bootstrap#load


    image.png

    org.apache.catalina.startup.Catalina#load()


    image.png

    ①、创建Digester

    获取file文件conf\server.xml,创建Digester对象。这个类的目的就是把server.xml中的层级结构和生命周期实现类都创建出来,包括容器类和监听器类。


    image.png

    org.apache.catalina.startup.Catalina#createStartDigester
    digester对象是解析server.xml文件


    image.png
    fakeAttributes通过键值对添加
    image.png

    digester的规则添加到Rules对象


    image.png
    digester解析文件reader = SAXParserImpl$JAXPSAXParser
    image.png
    image.png
    image.png

    ②、server.init初始化

    设置server的Catalina属性


    image.png

    开始server的init
    容器对象都实现了LifecycleBase声明周期方法,所以容器对象都会调用到org.apache.catalina.util.LifecycleBase#init,然后调用到容器的initInternal方法


    image.png
    org.apache.catalina.core.StandardServer#initInternal
    image.png
    ③、services.init()

    org.apache.catalina.util.LifecycleBase#init


    image.png

    org.apache.catalina.core.StandardService#initInternal


    image.png
    image.png
    ④、engine.init()

    org.apache.catalina.core.StandardEngine#initInternal


    image.png

    org.apache.catalina.core.StandardEngine#getRealm


    image.png
    org.apache.catalina.core.ContainerBase#initInternal
    image.png

    org.apache.catalina.core.ContainerBase#reconfigureStartStopExecutor
    创建内嵌的startStopExecutor执行器,用来处理部分容器类


    image.png
    ⑤、executor.init()和mapperListener..init()

    如果有自定义executors将会进行初始化


    image.png
    ⑥、connector.init()

    初始化连接
    初始化adapter
    org.apache.catalina.connector.Connector#initInternal


    image.png

    protocolHandler = Http11NioProtocol验证是否有效


    image.png
    image.png
    org.apache.coyote.http11.AbstractHttp11Protocol#init
    image.png
    org.apache.coyote.AbstractProtocol#init
    image.png

    org.apache.tomcat.util.net.AbstractEndpoint#init


    image.png
    org.apache.tomcat.util.net.AbstractEndpoint#bindWithCleanup
    image.png
    org.apache.tomcat.util.net.NioEndpoint#bind
    image.png
    org.apache.tomcat.util.net.NioEndpoint#initServerSocket
    创建serverSock对象,绑定端口,设置为非阻塞。服务端sockets启动
    image.png
    到这里便开启服务端Socket等待客户端连接

    3、start

    org.apache.catalina.startup.Bootstrap#start


    image.png
    3.1、StandardServer启动start

    org.apache.catalina.startup.Catalina#start


    image.png

    这里也会调用到父类LifecycleBase#start方法
    org.apache.catalina.util.LifecycleBase#start


    image.png
    org.apache.catalina.core.StandardServer#startInternal
    3.2、StandardService启动start

    开启services


    image.png

    开启一个startPeriodicLifecycleEvent,用来后台执行进行热加载和热部署


    image.png
    此时处于StandardService阶段,这里的lifecycleListeners 数量是0,所以setState方法什么都没做
    image.png
    3.3、StandardEngine启动start

    开启engine


    image.png

    开启engine后


    image.png
    主要步骤是:executor、mapperListener、connector的开启
    org.apache.catalina.core.StandardEngine#startInternal

    在StandardEngine阶段,lifecycleListeners有EngineConfig监听器


    image.png
    org.apache.catalina.core.ContainerBase#startInternal
    image.png
    步骤包括:cluster、realm的start调用、获取孩子容器StandardHost
    主要分析获取的孩子容器StandardHost
    把得到的孩子容器封装成StartChild任务类,使用startStopExecutor线程池开启任务
    image.png
    3.3.1、executor启动start

    executors线程池为null这里没有做什么

    3.3.2、mapperListener启动start
    image.png

    org.apache.catalina.mapper.MapperListener#startInternal


    image.png

    org.apache.catalina.mapper.MapperListener#addListeners
    listeners和lifecycleListeners添加MapperListener监听器,然后递归调用为孩子容器都添加这个MapperListener监听器


    image.png
    image.png
    org.apache.catalina.mapper.MapperListener#registerHost
    image.png

    org.apache.catalina.mapper.MapperListener#registerContext


    image.png
    image.png
    org.apache.catalina.mapper.MapperListener#prepareWrapperMappingInfo
    对每个wrapper寻找对应的映射关系并添加到wrappers中
    image.png
    image.png
    image.png
    3.3.3、connector启动start

    org.apache.catalina.core.StandardService#startInternal


    image.png

    org.apache.catalina.connector.Connector#startInternal


    image.png
    org.apache.coyote.AbstractProtocol#start
    image.png

    org.apache.tomcat.util.net.AbstractEndpoint#start


    image.png
    org.apache.tomcat.util.net.NioEndpoint#startInternal
    image.png
    创建executor工作线程池
    image.png
    poller线程启动
    acceptor线程启动
    image.png
    3.4、StandardHost启动start

    org.apache.catalina.core.ContainerBase.StartChild#call


    image.png

    lifecycleListeners包含HostConfig,所以在执行start之前
    org.apache.catalina.util.LifecycleBase#start


    image.png
    org.apache.catalina.util.LifecycleBase#setStateInternal
    发布一个lifecycleEvent = "before_start"事件
    image.png

    org.apache.catalina.util.LifecycleBase#fireLifecycleEvent
    HostConfig监听器处理before_start事件


    image.png
    org.apache.catalina.startup.HostConfig#lifecycleEvent
    image.png
    check()方法是periodic事件,用来热部署。beforeStart就是before_start事件
    org.apache.catalina.startup.HostConfig#beforeStart
    image.png
    得到webapps和conf/Catalina/loaclhost文件夹
    org.apache.catalina.core.StandardHost#startInternal
    image.png
    pipeline添加阈值通过addValve
    image.png

    调用父类方法
    StandardHost[localhost]寻找孩子容器,与StandardEngine过程相同


    image.png
    封装成StartChild交给startStopExecutor线程池处理
    3.5、StandardContext启动start
    image.png

    此时lifecycleListeners包括(CopyOnWriteArrayList 3个):ContextConfig、StandardHost$MemoryLeakTrackingListener 、ThreadLocalLeakPreventionListener
    org.apache.catalina.util.LifecycleBase#setStateInternal
    发布LifecycleState.STARTING_PREP事件是before_start


    image.png

    org.apache.catalina.util.LifecycleBase#fireLifecycleEvent


    image.png
    对三个监听器LifecycleListener调用lifecycleEvent
    org.apache.catalina.startup.ContextConfig#lifecycleEvent
    image.png
    image.png
    org.apache.catalina.startup.ContextConfig#fixDocBase

    调整docBase


    image.png
    org.apache.catalina.startup.ContextConfig#antiLocking
    对antiResourceLocking是true的处理,默认是false
    image.png
    另外两个LifecycleListener什么都没做
    StandardContext.startInternal()

    org.apache.catalina.core.StandardContext#startInternal
    ①、设置resources


    image.png

    org.apache.catalina.core.StandardContext#setResources


    image.png
    image.png
    把传入的resources赋值给this(StandardContext)的resources
    image.png

    ②、resources的启动
    org.apache.catalina.core.StandardContext#resourcesStart


    image.png
    StandardRoot实现了LifecycleBase,所以直接到startInternal方法
    org.apache.catalina.webresources.StandardRoot#startInternal
    image.png
    org.apache.catalina.webresources.StandardRoot#createMainResourceSet
    创建包含当前Context的路径的WebResourceSet并返回
    image.png
    image.png
    org.apache.catalina.webresources.StandardRoot#processWebInfLib
    image.png

    jar包资源resources也添加到StandradRoot的allResources中


    image.png
    image.png
    ③、创建webappLoader类,并设置到当前Context的loader中
    image.png
    image.png
    ④、当前应用加载器loader,启动start
    image.png
    WebappLoader实现了LifecycleBase
    org.apache.catalina.loader.WebappLoader#startInternal
    image.png
    org.apache.catalina.loader.WebappLoader#createClassLoader
    根据ParallelWebappClassLoader类的构造方法,传入父类加载器参是URLClassLoader。创建一个WebappClassLoaderBase对象。传入的resources是StandardRoot对象
    image.png
    image.png
    org.apache.catalina.loader.WebappClassLoaderBase#start
    把resources中的/WEB-INF/classes和/WEB-INF/lib目录添加到localRepositories中
    image.png
    image.png
    ⑤、解析web.xml文件
    image.png
    image.png
    org.apache.catalina.startup.ContextConfig#lifecycleEvent
    image.png
    image.png

    org.apache.catalina.startup.ContextConfig#webConfig


    image.png
    image.png
    org.apache.tomcat.util.descriptor.web.WebXmlParser#parseWebXml(org.xml.sax.InputSource, org.apache.tomcat.util.descriptor.web.WebXml, boolean)
    image.png
    image.png
    org.apache.tomcat.util.digester.Digester#parse(org.xml.sax.InputSource)
    image.png
    reader = SAXParserImpl$JAXPSAXParser
    image.png
    解析到servlets、servletMappings、 filters、 filterMaps等属性中
    image.png
    ⑥、寻找ServletContainerInitializer实现
    image.png
    org.apache.catalina.startup.ContextConfig#processServletContainerInitializers
    加载后的实现放入到detectedScis集合中
    image.png
    得到HandlesTypes注解
    image.png
    image.png
    ⑦、processClasses、合并web-fragment.xml、合并tomcat-web.xml
    image.png
    ⑧、JSP处理、把web.xml配置到Context
    org.apache.catalina.startup.ContextConfig#configureContext
    配置filter、filterMap、listener
    image.png
    SecurityConstraint、role、ContextService
    image.png
    servlet设置
    image.png
    ServletMapping、sessionConfig
    image.png
    配置PostConstruct、PreDestroy方法
    image.png
    ServletContainerInitializer实现添加到context中
    image.png
    ⑨、回调ServletContainerInitializers的onStartup方法
    image.png
    3.6、部署应用

    发布LifecycleState.STARTING是start的事件
    org.apache.catalina.core.ContainerBase#startInternal
    这里是StandardHost容器阶段。时机是在开始Host,把Host的孩子容器节点封装到StartChild任务类,在线程池startStopExecutor调用的,然后调用results的get回调方法,pipeline开始方法之后调用的


    image.png
    image.png

    org.apache.catalina.startup.HostConfig#lifecycleEvent


    image.png
    设置copyXML(false)、deployXML(true)、unpackWARs(true)、contextClass(org.apache.catalina.core.StandardContext)的参数值
    image.png
    org.apache.catalina.startup.HostConfig#start
    image.png
    deployApps()部署应用

    org.apache.catalina.startup.HostConfig#deployApps()


    image.png

    ①、deployDescriptors
    org.apache.catalina.startup.HostConfig#deployDescriptors
    处理部署在conf/Catalina/localhost/文件夹下XML形式的context


    image.png
    如果没有部署过则封装成DeployDescriptor任务类放到InlineExecutorService执行
    ②、deployWARs

    org.apache.catalina.startup.HostConfig#deployWARs
    部署war文件,webapps目录下以.war结尾的


    image.png
    如果没有部署过则封装成DeployWar任务类放到InlineExecutorService执行
    image.png
    ③、deployDirectories
    处理webapps目录下的文件夹
    org.apache.catalina.startup.HostConfig#deployDirectories
    image.png
    如果没有部署过则封装成DeployDirectory任务类放到InlineExecutorService执行

    总结:

    Tomcat的启动时通过启动类的main方法,主要有三步:初始化(init)、加载(load)、启动(start)
    1、初始化类加载器和Catalina类
    2、根据server.xml创建Digester,所定义的节点都会生成对应的对象,节点所处的层级也会解析出来,设置不同容器的pipeline基础的Value阈值。server、services、engine、executor、mapperListener、connector的初始化调用,其中最重要的是endpoint的serverSocket的创建
    3、StandardServer、StandardService和StandardEngine、StandardHost、StandardContext等容器的启动。
    ①、由于都实现了生命周期抽象类,所以会先调用LifecycleBase方法。在LifecycleBase方法内会使用调用setStateInternal发布一个事件,根据当前所处的容器阶段会调用相对应的监听器实现类。之后再调用所处容器的生命周期方法。
    ②、StandardHost和StandardContext都是在父类容器查找孩子容器然后封装成一个任务类放入到线程池中执行启动的。
    ③、在容器启动中,其中StandardContext的启动是最核心一个也是复杂的一个。主要包括WebappLoader类加载器创建和启动、解析web.xml文件(把解析后的值放到WebXML对象)、ServletContainerInitializers的查找及启动、把WebXML对象封装到当前Context对象等过程
    ④、容器启动后,就要部署应用。有三种部署形式,也都是封装成任务类放入到线程池内执行。部署应用分为部署server.xml中定义的Context和部署webapp文件夹下的Context

    相关文章

      网友评论

        本文标题:Tomcat之启动过程源码分析

        本文链接:https://www.haomeiwen.com/subject/vshjahtx.html