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.pngorg.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
网友评论