[spring-mvc] webApplicationContext

Spring中的Application实例是可以有范围(scope)的。在Spring MVC中,每个dispatcherServlet都持有一个自己的上下文对象WebApplicationContext,它又继承了根(root)WebApplicationContext对象已经定义的所有bean。这些继承的bean可以在具体的Servlet实现中被重载,在每个Servlet实例中你也可以定义其scope下的新bean。

servlet webApplicationContext里的bean可以注入root webApplicationContext里的bean,而root WebApplicationContext中定义的bean则不能注入servlet webApplicationContext中定义的bean
这里写图片描述
如上图的定义结构,可以像下面web.xml中配置

 
    <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath*:/applicationContext.xmlparam-value>
    context-param>

    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    listener>

    
    <servlet>
        <servlet-name>appServletservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>/WEB-INF/servlet-context.xmlparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
        <async-supported>trueasync-supported>
    servlet>

    <servlet-mapping>
        <servlet-name>appServletservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>

其中root WebApplicationContext是通过listener初始化的,servlet WebApplicationContext是通过servlet初始化的。
而在applicationContext.xml里通常只component-scan非Controller的类,如:

<context:component-scan base-package="io.github.test">
        <context:exclude-filter expression="org.springframework.stereotype.Controller"
            type="annotation" />
        <context:exclude-filter type="annotation"
            expression="org.springframework.web.bind.annotation.ControllerAdvice" />
    context:component-scan>

在servlet-context.xml里通常只component-scan Controller类, 如:

<context:component-scan base-package="io.github.test.web" use-default-filters="false">
        <context:include-filter expression="org.springframework.stereotype.Controller"
            type="annotation" />
        <context:include-filter type="annotation"
            expression="org.springframework.web.bind.annotation.ControllerAdvice" />
    context:component-scan>

如果不这样子分别component-scan的话,可能会出现bean重复初始化的问题。
上面是Spring官方开始时推荐的做法

root/servlet WebApplicationContext继承关系带来的麻烦

root WebApplicationContext里的bean可以在不同的servlet WebApplicationContext里共享,而不同的servlet WebApplicationContext里的bean互不干扰,这个本来是个很好的设计。
但是实际上还会有不少的问题:

  1. 不少开发者不知道Spring mvc里分有两个WebApplicationContext,导致各种重复构造bean,各种bean无法注入的问题。
  2. 有一些bean,比如全局的aop处理类,如果先root WebApplicationContext里初始化,那么servlet WebApplicationContext里的初始化的bean就没有处理到。如果在servlet WebApplicationContext里初始化,在root WebApplicationContext里的类就没有办法注入了。
  3. 区分哪此bean放在root/servlet很麻烦,不小心容易搞错,而且费心思。

一劳永逸的解决办法:bean都由root WebApplicationContext加载


相应的配置web.xml配置方法

<web-app>
    <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>/WEB-INF/servlet-context.xml, classpath:applicationcontext*.xmlparam-value>
    context-param>
    <servlet>
        <servlet-name>dispatcherservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>param-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
        <servlet-name>dispatcherservlet-name>
        <url-pattern>/*url-pattern>
    servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
    listener>
web-app>

参考文献

扯谈spring mvc之WebApplicationContext的继承关系:http://blog.csdn.net/hengyunabc/article/details/47072637

你可能感兴趣的:(spring-mvc)