释疑——Spring代码是如何在Tomcat容器中启动的
背景
最近在做基于注解的Spring的Web项目的练习,觉得这种方式更加方便,更加便于理解spring的运作机制,也方便以后接触Springboot。
Spring在Tomcat或者其他中间件中被启动时,主要分两块工作:
“|” 用来表示先后顺序
=========================第一部分工作=========================
Tomcat启动
|
Servlet容器启动,创建ServletContext
对象
|
根据Java SPI机制(查找所有jar包,找到META-INF/services/javax.servlet.ServletContainerInitializer
文件中指定的那个类),
Servlet容器调用实现了 ServletContainerInitializer
接口的类(即 SpringServletContainerInitializer
) 的onStartUp()
方法。
在此onStartUp方法中,根据注解 @HandleType("WebApplicationInitializer")
,找到它的实现类,然后执行他们的onStartUp()
方法。
如果想实现只通过注解完成web工程的开发,需要继承 AbstractDispatcherServletInitializer
这个抽象类。在它的onStartUp()
方法中做了两件事:
1、创建spring根容器和ContextLoaderListener
,绑定在一起,然后注册到ServletContext中。
2、创建DispacherServlet
和spring子容器,绑定在一起,并注册到ServletContext中。(其实父容器和子容器的Class类型是一样的,只是一个绑定在listener中,一个是绑定在servlet中)
注意:上面的部分主要是将spring运行需要的核心组件加入到了Tomcat的Servlet容器中(其中不仅有
ApplicationContext
,而且有ContextLoaderListener
),但截止到此刻,Spring还没有进行初始化!!!
========================第二部分工作========================
首先,了解下ServletContextListener
接口。Tomcat提供的一个负责监听Tomcat Servlet容器生命周期的监听器。实现此接口,并注册到Servlet容器中,就可以监听ServletContext的事件了。
Spring框架中的ContextLoaderListener
实现了ServletContextListener
接口。在上面提到的SPI机制的onStartUp()
方法中被注册到了ServletContext
中,所以,在Tomcat容器启动完成后,就会触发生命周期事件,从而回调此监听器。在此监听器中,才真正的对spring开始进行初始化的操作(即执行spring的refresh方法)
Tomcat启动
|
Servlet容器启动
|
SPI机制执行
|
Tomcat回调Servlet容器监听器的方法
|
ContextLoaderListener.contextInitialized()
//init root webapplication context
|
ContextLoaderListener.initWebApplicationContext(ServletContext)
//Initialize Spring's web application context for the given servlet context
|
ContextLoaderListener.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext,ServletContext)
|
ConfigurableWebApplicationContext.refresh()
//正式开始spring容器刷新
网友评论