配置 Root WebApplicationContext 以及 Servlet WebApplicationContext

AUTHOR | nicechi
类别 | Spring MVC
发表 | 2019-08-29 22:02:04
更新 | 2020-08-06 22:56:52

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 之间的关系:

图片从 docs.spring.io 中截取

 

在 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 将会生效,最后这些多个的配置文件将会整合成一个新的配置文件
<!--使用 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!


CATEGORY

TOP