版权声明:未经允许转载,将保留追究其法律责任 https://blog.csdn.net/qq_37025563/article/details/85626435
- 说明: 我们在以往的web项目里,在启动容器的话都要在web.xml配置文件中配置一个监听器
例:
<!-- 指定以Listener方式启动Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
-
这个web监听器就是容器的初始化的入口,首先看一下这个监听器的继承结构
-
ContextLoader类负责执行根应用程序上下文的实际初始化工作,ServletContextListener负责监听web容器的初始化与销毁
-
整个Spring mvc 容器的启动就是在contextInitialized()方法开始的,当整个web容器启动时,web容器就会调用该方法,这也是典型的观察者模式的应用
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() { }
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
- 接下来跟踪initWebApplicationContext(event.getServletContext())};
event.getServletContext()可以拿到seevlet的上下文对象,当做参数传入方法中,那么接下来我们看看核心方法中的代码
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 获取上下文域中属性,以String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"为key去取;如果已经存在WebApplicationContext对象则报错
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
// 如果WebApplicationContext为空则创建一个WebApplicationContext容器,方法里面有默认的选择容器的策略
// 默认容器存放在ContextLoader.properties文件中为XmlWebApplicationContext
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
// XmlWebApplicationContext 是ConfigurableWebApplicationContext的实现类
if (this.context instanceof ConfigurableWebApplicationContext) {
// 向上转型为ConfigurableWebApplicationContext
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
// 确定此应用程序上下文是否活动,即,*是否已刷新至少一次且尚未关闭。
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
// 获取父容器
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
// 这里面还是取拿取父容器
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 刷新web容器
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 刷新容器以后,放入servletContext域中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
// 判断当前线程所携带的类加载器,与加载ContextLoader类的类加载器是否一致,如果一致则存放到
// ClassLoader 的静态的当前容器变量中
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
// 如果不一致,则存放在private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread =
new ConcurrentHashMap<ClassLoader, WebApplicationContext>(1);中
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
- 目前我们对spring mvc 整个容器的初始化有了一个初步的概念,如果需要知道更多细节,比如怎么取加载我们的application.xml文件中的标签实现初始化,还请自行去研究
- 初次写个人博客,如有不正还请多多指出