tomcat启动后,到底对spring和spring mvc做了什么?
介绍
本文主要介绍:spring 整合了 spring mvc后,当tomcat启动时,spring 以及 spring mvc的相互以及关系启动顺序。
典型的父子关系
爸爸对儿子说:
1,"儿子,爸爸要离开这个家,等你长大了,就来某某地方找我"
2,"儿子,你有什么要求,尽管给老爸提,老爸能满足的都满足"
感动的背后 还是充满了内疚啊
启动顺序
总结
好好感受一下筷子兄弟《父亲》。
在web后端开发中,Spring无疑是龙头的老大。那么Spring是如何与tomcat容器关联起来的,本篇文章将讲述Spring容器是如何绑定到tomcat中的。
该接口是Servlet包中的接口,在Tomcat启动时会执行该接口对象的contextInitialized(ServletContextEvent sce)方法,当Tomcat关闭时会调用该接口对象的contextDestroyed(ServletContextEvent sce)方法。
该接口相当于Tomcat启动和关闭事件的回调接口,如果想在Tomcat启动或者关闭做一些事情,那么就可以实现该接口并将实现该接口的类通过web.xml配置文件进行注册。
public interface ServletContextListener extends EventListener {
public void contextInitialized(ServletContextEvent sce);
public void contextDestroyed(ServletContextEvent sce);
}
Spring利用了ServletContextListener的该特性,自定义ContextLoaderListener类实现ServletContextListener。通过ContextLoaderListener,Spring可以轻松的与Tomcat联系起来。(当然你也可以自定义自己的Listener,实现自己的容器)
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
除了定义类外,还需要在web的配置文件中将该类添加上,否则Tomcat启动时不会感知到Listener的存在。这就是为什么我们在构建Spring项目时在web.xml中配置ContextLoaderListener的原因,除此之外,还需要在web.xml中指定spring自定义的参数值,例如最常见contextConfigLocation参数,web.xml中的参数都会被tomcat解析,放到servletContext中,在ContextLoaderListener中spring会从servletContext中取出这些参数,并进行响应的操作。
org.springframework.web.context.ContextLoaderListener
tomcat服务启动时,会调用ContextLoaderListener的contextInitialized()方法,该方法调用了initWebApplicationContext()方法,下面看一下initWebApplicationContext()方法的实现。
整个spring环境的启动,都在该方法中了,简单来说就做了两件事件:
前期的准备工作如要如下:
源码如下:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//判断spring容器是否已经存在,如果存在则抛出异常,不能存在两个spring容器
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 {
//创建WebApplicationContext对象,该对象的默认实现放在spring-web jar包下的ContextLoader.properties中
//默认为org.springframework.web.context.support.XmlWebApplicationContext
if (this.context == null) {
//该方法创建出来的都是ConfiguableWebApplicationContext对象
//web启动,会创建该对象
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof 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
//设置父类,可以不用考虑,需在在web.xml中指定才会设置
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);
}
//重点操作,配置并更新WebApplicationContext
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//将webApplicationContext存到servletContext中,表示该容器已经生成完
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
//类加载器相关内容,本文不做介绍
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
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;
}
}
作者:逍遥无极
链接:https://www.jianshu.com/p/3be45ce2256a
●史上最强Tomcat8性能优化
●阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路
●B2B电商平台--ChinaPay银联电子支付功能
●学会Zookeeper分布式锁,让面试官对你刮目相看
●SpringCloud电商秒杀微服务-Redisson分布式锁方案
查看更多好文,进入公众号--撩我--往期精彩
一只 有深度 有灵魂 的公众号0.0