类图
组件关系
启动流程
Tomcat有三种启动方式
- From the command line
- From a Java program as an embedded server
- Automatically as a Windows service
Bootstrap初始化
-
设置类加载器
- commonLoader (common)-> System Loader
- sharedLoader (shared)-> commonLoader -> System Loader
- catalinaLoader(server) -> commonLoader -> System Loader
- 默认情况下,commonLoader用于sharedLoader和serverLoader
-
通过反射加载启动类
- org.apache.catalina.startup.Catalina
- setParentClassloader-> sharedLoader
- Thread.contextClassloader-> catalinaLoader
-
完成Bootstrap.daemon.init(),即完成初始化
输入命令行参数
假设命令为start
-
Catalina.setAwait(true)
阻塞当前daemon -
Catalina.load()
- initDirs()
- initNaming()
- createStartDigester()
- 加载server.xml并使用Digester对其解析
- 将System.out和System.err分配给SystemLogHandler类
- 在所有组件上调用初始化,这使每个对象向JMX代理。在调用过程中,连接器还会初始化适配器(它是执行请求预处理的组件)。默认的适配器协议是Http1.1
-
Catalina.start()
-
启动NamingContext并将所有JNDI引用绑定到其中
-
启动
Server
下的services:
S t a n d a r d S e r v i c e → s t a r t s E n g i n e ( C o n t a i n e r B a s e → R e a l m , C l u s t e r , e t c ) StandardService\rightarrow starts Engine(ContainerBase\rightarrow Realm, Cluster,etc) StandardService→startsEngine(ContainerBase→Realm,Cluster,etc) -
在容器(StandardEngine)的生存期内,有一个后台线程继续检查上下文是否已更改。如果上下文发生变化(war,xml的时间戳),然后重新加载(停止/删除/部署/启动)
-
请求过程
Coyote负责Connector模块,Calatina负责容器模块
- 该请求由正在ThreadPoolExecutor类中等待的单独线程接收
- ThreadPoolExecutor分配一个TaskThread来处理请求。还会向Catalina容器提供JMX对象名
- 一般情况下,会调用Coyote Http11Processor进行协议解析,并通过Processor读取数据。这个Processor还将继续检查socket的inputStream直到到达保持活动点或连接断开
- 在调永Http11Processor解析Http请求的过程中,会通过缓冲区类Http11InputBuffer解析请求行,端口等相关协议内容
- Processor中包含对CoyoteAdapter的引用。当Http11Processor解析完请求之后,会调用其引用的Adapter的
service(request, response)
方法。该方法负责唤醒所有的监听器。同时通过Mapper解析所有内容并将其与request,cookie,context进行关联 - 之后,
CoyoteAdapter
通过connector.getService().getContainer()
调用容器StandardEngine,并且调用其getPipeline().getFirst().invoke(request,response)
方法从Engine级别启动HTTP请求到Catalina容器 (getFirst的返回值是Valve)- 从这里可以看出每次调用都借助了责任链模式
- 默认的Engine只有一个Valve,即StandardEngineValve,即通过该valve的invoke去调用
StandardEngine
tandardEngineValve.invoke()
中会再次通过host.getPipeline().getFirst().invoke(request, response);
去调用Host类的管道去唤醒Host容器- StandardHost有两个默认valve,即StandardHostValve和ErrorrEportValve
- StandardHostValve会关联当前线程的类加载器,同时也会检索与请求关联的Manager和Session,如果Session存在,则保持会话状态
- 之后
StandardHostValve.invoke()
会再次通过context.getPipeline().getFirst().invoke(request, response);
唤醒在与request关联的context上的pipeline- 先唤醒
FormAuthenticao
这个Valve,再唤醒StandardContextValve
StandardContextValve
调用与context关联的所有ContextListener
- 先唤醒
- 接下来,通过
wrapper.getPipeline().getFirst().invoke(request, response);
唤醒Wrapper组件(StandardWrapperValve)中的pipeline- 在这个过程中,调用Jsp Wrapper(Jasper),实际编译JSP,然后调用实际的Servlet
- 在这个过程中,调用Jsp Wrapper(Jasper),实际编译JSP,然后调用实际的Servlet
参考资料