在springmvc项目中,可以有多个容器,而且容器有上下层关系,此处的容器指的是spring容器,它是springmvc的父容器,springmvc容器将在下一章讲解。
WebApplicationContext
web环境下spring默认使用的是WebApplicationContext,它是一个接口,看一下WebApplicationContext的定义:
1 | public interface WebApplicationContext extends ApplicationContext { |
(1)WebApplicationContext接口本身中的内容并不多,可以看到它继承了ApplicationContext,有一个ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE成员变量,这个变量用于将IoC容器设置到ServletContext时的key,之后就可以从ServletContext中获取IoC容器。
1 | servletContext.setAttribute(WebApplicationConservletContexttext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); |
(2)既然WebApplicationContext只是一个接口,那么一定有一个它的实现类,作为IoC容器的实现,这个类就是XmlWebApplicationContext。
XmlWebApplicationContext
Spring使用XmlWebApplicationContext作为默认的WebApplicationContext容器实现,从继承关系中可以看到,XmlWebApplicationContext继承了WebApplicationContext,其实从名字上就可以看出,XmlWebApplicationContext也是ApplicationContext容器的实现,在ApplicationContext的基础之上,增加了对Web环境和XML配置定义的处理。
1 | public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext { |
从XmlWebApplicationContext的启动过程来看,与IoC容器的初始化过程基本差不多,只不过在Web环境中,已经定义好了一个默认的配置文件,即WEB-INF/appicationContext.xml,下面看一下如何进入到XmlWebApplicationContext的loadBeanDefinitions方法中的。
ContextLoaderListener
ContextLoaderListener是Web容器中配置的监听器,WebApplicationContext容器的载入就是它负责的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
public void contextInitialized(ServletContextEvent event) {
// 初始化WebApplicationContext,具体的工作在ContextLoader中完成
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
// 销毁WebApplicationContext
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
ContextLoaderListener的contextInitialized方法中调用了initWebApplicationContext方法初始化web容器,该方法是在它的父类ContextLoader中实现的。
ContextLoader
1 | public class ContextLoader { |
在ContextLoader类中,存在一个WebApplicationContext类型的字段context, 这个变量就是Web环境中的IoC容器,也会配置在ServletContext的根上下文中,ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为属性名,已经在WebApplication中定义为了一个常量。
initWebApplicationContext方法,是启动IoC容器的入口:
(1)如果容器还没有创建,会调用createWebApplicationContext方法创建IoC容器,在该方法中,会调用determineContextClass方法判断使用哪种IoC容器,如果没有设置contextClass参数,就使用默认的容器即WebApplicationContext。
(2)接着会判断创建的容器是否是ConfigurableWebApplicationContext的实例,如果是,将设置双亲上下文,并调用configureAndRefreshWebApplicationContext方法,将当前的serveltContext设置到Ioc容器中,最后调用容器的refresh()方法,完成容器的初始化。
(3)最后会把容器设置到ServletContext的根上下文中,并将容器返回。
AbstractApplicationContext
再回顾一下XmlWebApplicationContext的继承关系,它继承了AbstractRefreshableApplicationContext,AbstractRefreshableApplicationContext又继承了AbstractApplicationContext方法,refresh方法就是在AbstractApplicationContext实现的,之后的流程就和IoC容器启动过程一样了。
AbstractApplicationContext中的refresh()方法:
1 | public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { |
AbstractRefreshableApplicationContext
refresh方法中调用了调用AbstractRefreshableApplicationContext的prepareBeanFactory方法,在该方法中对BeanDefinition进行了载入:
1 | public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { |
到此,如何进入到XmlWebApplicationContext的loadBeanDefinitions方法中的过程已经很明了了。
参考:
spring技术内幕:深入解析spring架构与设计原理
Spring版本:5.0.5