Tomca组件结构
connector:主要负责接受浏览器发送过来的tcp连接请求,创建一个request和response
container:接受request和response,并开启线程处理请求封装结果
service:结合connector和container,对外提供接口服务,一个service可以有多个connector(多种连接协议)和一个container(engine,可以理解为servlet容器)
server:为service提供生存环境,负责他的生命周期,它可以包含多个service服务
Tomcat容器结构
Engine:servlect的顶层容器,包含一个或多个Host子容器;
Host:虚拟主机,负责web应用的部署和context的创建
Context:web应用上下文,包含多个wrapper,负责web配置的解析、管理所有的web资源
Wrapper:最底层的容器,是对servlet的封装,负责servlet实例的创建、执行、销毁
Tomcat启动过程
Tomcat启动时,执行启动脚本startup.sh->catalina.sh->Bootstrap->Bootstrap.main方法
1 | java复制代码 public static void main(String args[]) { |
1. Catalina.load()
所以最后Bootstrap.main()->Catalina.load(),load方法中主要做了2个事情:
- 创建Digester类,解析conf/server.xml文件
- 调用server.init()进行初始化server
1 | java复制代码 protected String configFile = "conf/server.xml"; |
getServer.init()->LiftcycleBase.init():
- 更新server的LifecycleState,并发布状态变化事件
- 调用StandServer.initInternal()进行server的初始化
1 | java复制代码public abstract class LifecycleBase implements Lifecycle { |
1 | java复制代码 protected void initInternal() throws LifecycleException { |
StandServer.initInternal()->LeftcycelBase.init()->StandService.initeInternal(),standService.initernel()主要实现:
- 初始化engine
- 初始化connectors
1 | java复制代码 protected void initInternal() throws LifecycleException { |
初始化engine.init()->LifecycleBase.init()->StandardEngine.initernal()
初始化connetor.init()->LiftcycleBase.init()->Connector.initernal()->ProtocolHandler.init()
2. Catalina.start()
1 | java复制代码 public void start() { |
Catalina.start()->LifecycleBase.start()->StandardServer.startIniternal()
1 | java复制代码 @Override |
StandardServer.startIniternal()->LifecycleBase.start()->StandardService.startIniternal()
1 | java复制代码 protected void startInternal() throws LifecycleException { |
1)engine.start()->LifecycleBase.start()->engine.startInternal()->ContainerBase.startInternal()
1 | java复制代码 protected synchronized void startInternal() throws LifecycleException { |
StandardEngine的子容器是Host,所以:ContainerBase.startInternal()->LifecycleBase.start()->发布事件->HostConfig监听此事件
1 | java复制代码 public void lifecycleEvent(LifecycleEvent event) { |
到这里StandardContext算是创建了,并且是Host的子容器,然后回到LifecycleBase.start(),执行startInternal()->StandardHaost.startInternal()->ContainerBase.startInternal(),最终又回到父类ContainerBase的startIniternal()方法中,重复执行StandardContext的事件监听ContextConfig和startInternal():
- ContextConfig的事件监听中,会加载项目的web.xml文件
1 | java复制代码 @Override |
- 进入StandardContext.startIniternal()中
1 | java复制代码 protected synchronized void startInternal() throws LifecycleException { |
监听:这个监听就是web.xml中配置的,就是启动spring容器的入口
1 | xml复制代码<!-- listener --> |
初始化servlet:StandardContext.loadOnStartup()->StandardWrapper.load()
1 | java复制代码@Override |
最后调用的是:GenericServlet.init()
1 | java复制代码@Override |
GenericServlet.init()->HttpServletBean.init()->FramworkServlet.initServletBean(),此时已经进入spring-webmvc.jar
1 | java复制代码public final void init() throws ServletException { |
1 | java复制代码 protected final void initServletBean() throws ServletException { |
最后的最后进入:DispatcherServlet.onRefresh()
1 | java复制代码protected void onRefresh(ApplicationContext context) { |
最后附上一张DispatcherSerlvet的类图:
2)还有个Connector的初始化:connector.start()->LifecycleBase.start()->Connector.startIniternal()->protocalHandler.start()
1 | java复制代码 protected void startInternal() throws LifecycleException { |
总结一下子:
* 启动脚本**startup.sh**,最终执行Bootstrap.main(),且会把命令(start、stop等)作为参数传入,不同参数会调用不同的方法 * 当命令是start时,**Bootstrap.main()**会调用**Catalina.load()**和**Catalina.start()**
* 在Catalina.load()中,解析**conf/server.xml**,最后调用getServer.init(),对**server**初始化 4. 调用getServer.init(),会进入**LifecycleBase.init()**,这个方法中会先这是server状态为initializing且发布事件,再调用StandardServer.initInternal() 5. 在StandardServer.initInternal()中,会循环调用service.init()方法,会先进入LifecycleBase.init(),然后进入**StandardService.initInternal()** 6. 在StandardService.initInternal()中会初始化**engine**和**connectors**
* Catalina.start(),最后调用getServer.start(),进入LifecycleBase.start(),最后进入StandardServer.startIniternal() 2. 在**StandardServer.startIniternal**()中,会启动engine.start()和connector.start() 3. 在engine.start()中,调用**ContainerBase.startIniternal()**,会将子容器Host的启动任务提交到线程池中,**Host容器启动**过程: * 先发布事件,且HostConfig监听到这个事件,在HostConfig中会发布web项目,且创建当前web项目的StandardContext,然后把这个**StandardContext添加到Host的子容器中** * 然后执行StandardHost.startIniternal(),这个方法中又回到父类ContainerBase.startIniternal(),然后**重复提交StandardContext的启动任务到线程池中** 4. **StandardContext的启动过程**: * 发布事件,ContextConfig监听到这个事件,ContextConfig中加载并**解析项目的web.xml文件**,初始化配置的Listener、Filter、Servlet等信息,**servlet会解析成Wrapper**,**然后添加到Context的子容器中** * 然后调用**StandardContext.startIniternal**(),启动Context,这里会调用web.xml配置的监听**contextInitialized(),spring容器在这里得到创建** * 在StandardContext.startIniternal()中,然后加载Servlet,最终会调用spring-webmvc.jar中**DispatcherSerlvet.onRefresh()**,**加载Serlvet的七大组件**
再来个简单版的总结
Tomcat启动分成2个部分:
- 组件的初始化
- 容器的启动
其中组件包括:Server->Services->Engine->Connectors
容器包括:Engine->StandardHost->StandardContext->StandardWrapperweb项目的加载、Spring容器的初始化入口、Servlet容器的加载都在第二步,也就是Catalina.start()中
- web项目的加载:在启动Host容器前发布的事件,也就是监听HostConfig.start()中,并且创建子容器StandardContext
- Spring容器的初始化入口:在StandardContext启动过程中执行了web.xml中配置的ServletContextListener的实现类的contextInitialized()
- Servlet容器的加载:在StandardContext启动过程中执行的loadOnStartup(),最终调用DispatcherServlet.onRefresh(),初始化了Servlet的九大组件
留个大疑问
上文中的ServletContainerInitializer的作用是啥?有什么应用?可以怎么拓展?
作用:它是Servlet3.0提供的接口,只有一个方法,主要作用替代web.xml,通过初始化自定义的Listener、Filter、Servlet等信息
1 | java复制代码public interface ServletContainerInitializer { |
应用:spring-web.jar中,SpringServletContainerInitializer实现了此接口
1 | java复制代码// 1)通过此注解将WebApplicationInitializer类,添加到onStartup方法的第一个参数中 |
SpringServletContainerInitializer在Tomcat启动时,容器初始化阶段初始化StandardContext时,被调用:
1 | java复制代码 protected synchronized void startInternal() throws LifecycleException { |
SpringServletContainerInitializer是如何加载到的?毕竟在第三方jar包中,也是在Tomcat启动初始化容器StandardContext之前,发布的事件,在事件监听ContextConfig中加载的:(方法链路:lifecycleEvent()->configureStart()->webConfig()->processServletContainerInitializers()->WebappServiceLoader.load()),spring-web.jar的**classpath/META-INF/services/**路径下配置了需要初始化的ServletContianerInitializer,由Tomcat的ContextConfig加载初始化,在StandardContext中调用
1 | java复制代码 protected void processServletContainerInitializers(){ |
自定义:ServletContainerInitializer
1 | java复制代码//容器启动的时候会将@HandlesTypes指定的这个类型下面的子类(实现类,子接口等)传递过来; |
参考:
😈如果有错误请大家指正…
本文转载自: 掘金