springMVC在tomcat中的初始化

在spring Web中,需要初始化IOC容器,用于存放我们注入的各种对象。当tomcat启动时首先会初始化一个web对应的IOC容器,用于初始化和注入各种我们在web运行过程中需要的对象。当tomcat启动的时候是如何初始化IOC容器的,我们先看一下在web.xml中经常看到的配置:

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		classpath:applicationContext.xml
	</param-value>
</context-param>
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

ContextLoaderListener是一个监听器,其实现了ServletContextListener接口,其用来监听Servlet,当tomcat启动时会初始化一个Servlet容器,这样ContextLoaderListener会监听到Servlet的初始化,这样在Servlet初始化之后我们就可以在ContextLoaderListener中也进行一些初始化操作。看下面的ServletContextListener的源码也是比较简单的,ContextLoaderListener实现了ServletContextListener接口,所以会有两个方法contextInitialized和contextDestroyed。web容器初始化时会调用方法contextInitialized,web容器销毁时会调用方法contextDestroyed。

 

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
 
	public ContextLoaderListener() {
	}
 
	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}
	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		//在父类ContextLoader中实现
		initWebApplicationContext(event.getServletContext());
	}
	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
 
}

ContextLoaderListener的方法contextInitialized()的默认实现是在他的父类ContextLoader的initWebApplicationContext方法中实现的,意思就是初始化web应用上下文。他的主要流程就是创建一个IOC容器,并将创建的IOC容器存到servletContext中,ContextLoader的核心实现如下:

initWebApplicationContext函数:
 

//初始化WebApplicationContext,IOC容器
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		//判断web容器中是否已经有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
			if (this.context == null) {
				//最终得到的是XmlWebApplicationContext
				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
					//判断是否已经有父容器
					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");
			}
			//初始化 WebApplicationContext完成并返回
			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;
		}
	}

这里需要注意的是:

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);
					}

springMVC初始化时会先查看是否含有父容器(通常是spring),如果有,则cwac.setParent(parent);,至此,springMVC和spring则为父子容器,springMVC作为子容器可以调用父容器spring的bean对象,比如说在controller中注入service。

springMVC父容器初始化流程图(盗图)如下:

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值