WebApplicationContext
ApplicationContext 是一个接口,它是 Spring Context 模块的核心,从某种程度上可以说整个的 Spring 程序就是以这个对象为基础而展开工作的。
WebApplicationContext 是 ApplicationContext 的一个子接口,它在 ApplicationContext 的基础上扩展添加了 web application 所需要的一些功能。
Root WebApplicationContext
在 Spring MVC 中,一个 Web Application 只能拥有一个全局的 WebApplicationContext,而每一个 DispatcherServlet 可以拥有各自的 WebApplicationContext,这时候全局的 WebApplicationContext 就被称之为 Root WebApplicationContext ,而每一个 DispatcherServlet 所拥有的 WebApplicationContext 就被称之为 Servlet WebApplicationContext。下图所展示的就是 Root Web Application Context 与 Servlet WebApplicationContext 之间的关系:
在 web.xml 中配置 Root WebApplicationContext
使用 ContextLoaderListener 在 web.xml 中创建 Root WebApplicationContext:
- ContextLoaderListener 用来在 Servlet 开始或结束时开启或关闭 WebApplicationContext
- ContextLoader 的初始化需要两个 Servlet Context Params,分别为 contextClass 和 contextConfigLocation
- contextClass 用来指定配置文件的类型(XML 还是 JAVA 配置类),其值可以为:
- org.springframework.web.context.support.XmlWebApplicationContext (XML 配置文件),如果没有指定 contextClass 的话,默认为 XmlWebApplicationContext
- org.springframework.web.context.support.AnnotationConfigWebApplicationContext (JAVA 配置类)
- contextConfigLocation 用来指定配置文件所在的位置:
- 如果 contextClass 为 XmlWebApplicationContext 的话指定的就是 XML 配置文件所在的位置,如果 contextClass 为 AnnotationConfigWebApplicationContext 的话指定的就是 JAVA 配置类所在的位置,如果没有指定 contextConfigLocation 的话,则默认值为 " /WEB-INF/applicationContext.xml "
- contextConfigLocation 可以指定多个的配置文件,如果多个配置文件同时声明了同一个 Bean 的话,则最后一个声明的 Bean 将会生效,最后这些多个的配置文件将会整合成一个新的配置文件
- contextClass 用来指定配置文件的类型(XML 还是 JAVA 配置类),其值可以为:
<!--使用 XML 配置文件创建 RootApplicationContext-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--如果为 JAVA 配置类的话,就使用 org.springframework.web.context.support.AnnotationConfigWebApplicationContext -->
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
</context-param>
<!--如果为 JAVA 配置类的话,就是配置类所在的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/applicationContext.xml</param-value>
</context-param
使用编程的方式来配置 Root WebApplicationContext
通过实现 WebApplicationInitializer 接口
Servlet 3.x 提供了一系列的 API ,通过这些 API 可以直接通过编程的方式来代替 web.xml,我们可以通过 WebApplicationInitializer 来注册 ContextLoaderListener:
//方法一
//此方法本质上来说其实就是上面所讲的通过 web.xml 创建 Root ApplicationContext 的方法
public class ApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//.setInitParamneter() 其实就相当于<context-param> ... </context-param>
servletContext.setInitParameter("contextClass","org.springframework.web.context.support.XmlWebApplicationContext");
servletContext.setInitParameter("contextConfigLocation","/WEB-INF/applicationContext.xml");
//此时 ContextLoaderListener 将使用刚刚所设置的 contextClass 和 contextConfigLocation 的值来创建 WebApplicationContext
servletContext.addListener(new ContextLoaderListener());
}
}
//方法二
//此方法稍微比方法一简单一点,不用去设置 contextClass 和 contextConfigLocation 的值
//只要直接将 XmlWebApplicationContext 或者 AnnotationConfigWebApplicationContext 对象作为构造参数赋给 ContextLoaderListener 即可
public class ApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
XmlWebApplicationContext webApplicationContext=new XmlWebApplicationContext();
webApplicationContext.setConfigLocation("/WEB-INF/applicationContext.xml");
servletContext.addListener(new ContextLoaderListener(webApplicationContext));
}
}
通过继承 AbstractContextLoaderInitializer 来实现
WebApplicationInitializer 可以实现很多功能,但是如果仅仅用来创建 Root WebApplicationContext 的话难免有点复杂。
这个时候可以使用 AbstractContextLoaderInitializer 来创建,此方法需要实现 protected WebApplicationContext createRootApplicationContext() 方法,很明显从字面上就可以看出来这个方法专门用来创建 Root WebApplicationContext ,而且明显比前面的几种方法更为便捷,只需要创建一个 WebApplicationContext 对象即可。
public class WebApplicationContextInitialializer extends AbstractContextLoaderInitializer {
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext annotationConfigWebApplicationContext=
new AnnotationConfigWebApplicationContext();
annotationConfigWebApplicationContext.register(ApplicationConfiguration.class);
return annotationConfigWebApplicationContext;
}
}
Servlet WebApplicationContext
DispatcherServlet 本质上就是一个 Servlet(org.springframework.web.servlet.DispatcherServlet),通常用来接收 request,然后将其转发给相对应的 Controller。
Root WebApplicationContext 是每一个 Spring Web Application 都可以拥有的,但是 Servlet WebApplicationContext 是 Spring MVC 所特有的。
Servlet WebApplicationContext 可以获取 Root WebApplicationContext 中的对象,但是 Root WebApplicationContext 不能获取 Servlet WebApplicationContext 中的对象。
在 web.xml 中配置 Servlet WebApplicationContext
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 表明配置文件的类型-->
<!-- 如果是 XML 配置文件的话,contextClass 的值就为 org.springframework.web.context.support.XmlWebApplicationContext-->
<!-- 如果是 JAVA 配置类的话,contextClass 的值就为 org.springframework.web.context.support.AnnotationConfigWebApplicationContext-->
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
</init-param>
<!-- 表明配置文件所在的位置-->
<!-- 如果是 XML 配置文件的话,contextConfigLocation 的值就是 XML 配置文件所在的位置-->
<!-- 如果是 JAVA 配置类的话,contextConfigLocation 的值就是配置类所在的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
使用编程的方式来配置 Servlet WebApplicationContext
如同配置 RootWebApplicationContext 一样,依然可以使用 Servlet 3.x 所提供的 API 来配置 Servlet WebApplicationContext。
通过实现 WebApplicationInitializer 接口
public class ApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
...
ServletRegistration.Dynamic dynamic=
servletContext.addServlet("dispatcher",new DispatcherServlet());
//设置 servlet 的 mapping 地址
dynamic.addMapping("/");
dynamic.setLoadOnStartup(1);
//设置 contextClass
dynamic.setInitParameter("contextClass","org.springframework.web.context.support.XmlWebApplicationContext");
//设置 contextConfigLocation
dynamic.setInitParameter("contextConfigLocation","/WEB-INF/dispatcher-servlet.xml");
...
}
}
通过继承 AbstractDispatcherServletInitializer 接口
AbstractDispatcherServletInitializer 也是 WebApplicationInitializer 的实现类
public class DispatcherServletInitializer extends AbstractDispatcherServletInitializer {
@Override
protected WebApplicationContext createServletApplicationContext() {
//如果是 XML 配置文件,就创建 XmlWebApplicationContext 对象
//如果是 JAVA 配置类的话,就创建 AnnotationConfigWebApplicationContext 对象
XmlWebApplicationContext xmlWebApplicationContext=
new XmlWebApplicationContext();
xmlWebApplicationContext.setConfigLocation("/WEB-INF/dispatcher-servlet.xml");
return xmlWebApplicationContext;
}
//设置 DispatcherServlet 的映射
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//也可以创建 Root WebApplicationContext
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
Root WebApplicationContext 和 Servlet WebApplicationContext 的联系
- Root WebApplicationContext 是每一个 Spring Web Application 都有的,但是 Servlet WebApplicationContext 是 Spring MVC 特有的
- Root WebApplicationContext 可以认为是 Servlet WebApplicationContext 的 parent,Servlet WebApplicationContext 是 Root WebApplicationContext 的 children
- Root WebApplicationContext 中所定义 Bean 可以被任何一个 Servlet WebApplicationContext 所使用,但是 Servlet WebApplicationContext 中所定义的 Bean 不可以被 Root WebApplicationContext 所使用
- 多个 Servlet WebApplicationContext 之间是相互独立的,他们之间所定义的 Bean 只能被自己所使用
最后,希望这篇文章能带给你点启发,Have Fun!