首页 > 代码库 > Spring: DispacherServlet和ContextLoaderListener中的WebApplicationContext的关系

Spring: DispacherServlet和ContextLoaderListener中的WebApplicationContext的关系

在Web容器(比如Tomcat)中配置Spring时,你可能已经司空见惯于web.xml文件中的以下配置代码:

 

<context-param>        <param-name>contextConfigLocation</param-name>        <param-value>/WEB-INF/applicationContext.xml</param-value>    </context-param>                                                                                                                                                 <listener>        <listener-class>            org.springframework.web.context.ContextLoaderListener        </listener-class>    </listener>                                                                                                                                                 <servlet>        <servlet-name>mvc-dispatcher</servlet-name>        <servlet-class>            org.springframework.web.servlet.DispatcherServlet        </servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>                                                                                                                                             <servlet-mapping>        <servlet-name>mvc-dispatcher</servlet-name>        <url-pattern>/</url-pattern>    </servlet-mapping>

 

以上配置首先会在ContextLoaderListener中通过<context-param>中的applicationContext.xml创建一个ApplicationContext,再将这个ApplicationContext塞到ServletContext里面,通过ServletContext的setAttribute方法达到此目的,在ContextLoaderListener的源代码中,我们可以看到这样的代码:

 

servletContext.setAttribute(              WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

 

以上由ContextLoaderListener创建的ApplicationContext是共享于整个Web应用程序的,而你可能早已经知道,DispatcherServlet会维持一个自己的ApplicationContext,默认会读取/WEB-INFO/<dispatcherServletName>-servlet.xml文件,而我么也可以重新配置:

 

<servlet>    <servlet-name>       customConfiguredDispacherServlet   </servlet-name>   <servlet-class>       org.springframework.web.servlet.DispatcherServlet   </servlet-class>   <init-param>       <param-name>           contextConfigLocation       </param-name>       <param-value>           /WEB-INF/dispacherServletContext.xml       </param-value>   </init-param>   <load-on-startup>1</load-on-startup></servlet>

 

问题是:以上两个ApplicationContext的关系是什么,它们的作用作用范围分别是什么,它们的用途分别是什么?

 

ContextLoaderListener中创建ApplicationContext主要用于整个Web应用程序需要共享的一些组件,比如DAO,数据库的ConnectionFactory等。而由DispatcherServlet创建的ApplicationContext主要用于和该Servlet相关的一些组件,比如Controller、ViewResovler等。

 

对于作用范围而言,在DispatcherServlet中可以引用由ContextLoaderListener所创建的ApplicationContext,而反过来不行。

 

在Spring的具体实现上,这两个ApplicationContext都是通过ServletContext的setAttribute方法放到ServletContext中的。但是,ContextLoaderListener会先于DispatcherServlet创建ApplicationContext,DispatcherServlet在创建ApplicationContext时会先找到由ContextLoaderListener所创建的ApplicationContext,再将后者的ApplicationContext作为参数传给DispatcherServlet的ApplicationContext的setParent()方法,在Spring源代码中,你可以在FrameServlet.java中找到如下代码:

 

wac.setParent(parent);

 

其中,wac即为由DisptcherServlet创建的ApplicationContext,而parent则为有ContextLoaderListener创建的ApplicationContext。此后,框架又会调用ServletContext的setAttribute()方法将wac加入到ServletContext中。

 

当Spring在执行ApplicationContext的getBean时,如果在自己context中找不到对应的bean,则会在父ApplicationContext中去找。这也解释了为什么我们可以在DispatcherServlet中获取到由ContextLoaderListener对应的ApplicationContext中的bean。

Spring: DispacherServlet和ContextLoaderListener中的WebApplicationContext的关系