ContextLoaderListener介绍

在给新同事培训Spring MVC时,有人问:可以不配置ContextLoaderListener吗

所谓ContextLoaderListener,就是在web部署描述符即web.xml里面经常配置的一个监听器,如下

[html]  view plain  copy
  1. <listener>  
  2.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  3. </listener>  

那么配合它一起使用的,经常是context-param,用来指定Spring要加载的配置文件,比如

[html]  view plain  copy
  1. <context-param>  
  2.     <param-name>contextConfigLocation</param-name>  
  3.     <param-value>/WEB-INF/teach-servlet.xml</param-value>  
  4. </context-param>  
  5.   
  6. <!-- Spring MVC -->  
  7. <servlet>  
  8.     <servlet-name>teach</servlet-name>  
  9.     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  10.     <load-on-startup>1</load-on-startup>  
  11. </servlet>  
  12. <servlet-mapping>  
  13.     <servlet-name>teach</servlet-name>  
  14.     <url-pattern>*.action</url-pattern>  
  15. </servlet-mapping>  

上面两段就是在使用Spring MVC时,常用的配置,DispatcherServlet作为Spring MVC控制器的核心调度器

至于 teach-servlet.xml 就是配置一些Spring MVC需要使用的视图解析器等等


那么问题是:listener节点可以不配置吗?答案是肯定的:可以不做任何配置!

查看了ContextLoaderListener源代码,发现它继承自ContextLoader,并且实现ServletContextListener接口

肯定得实现这个接口了,不然怎么作为Servlet的监听器呢。。。

ContextLoaderListener 源代码很简单,核心是实现了 ServletContextListener 的contextInitialized和contextDestroyed方法

我们看下类图结构,只列出一部分属性和方法


因为 contextInitialized和contextDestroyed 方法分别调用了 ContextLoader里面的initWebApplicationContext和closeWebApplicationContext方法

所以核心最终还是 ContextLoader 实现了这个监听器,那这个监听器实现了什么功能呢,我们发现有两个重要属性

contextConfigLocation:即在web.xml里面指定的配置文件所在目录,如果不指定,Spring 会加载WEB_INF目录下,符合 *Context.xml 或 spring*.xml 规则的文件

currentContextPerThread:保存了当前WebApplicationContext


其实监听器的加载过程可以描述为:

先判WebApplicationContext是否已存在,不存在的话则初始化一个XmlWebApplicationContext(WebApplicationContext的子类),并把该实例put到 currentContextPerThread 中。而初始化 XmlWebApplicationContext 时,就跟我们使用 new ClassPathXmlApplicationContext(contextConfigLocation)一样

将我们配置的各种bean都添加到XmlWebApplicationContext中,所以我们知道 ApplicationContext 提供各种 getBean的方法。。。

并且可以发现 ContextLoader还提供了获取当前 WebApplicationContext的静态方法:之所以能获取,是因为initWebApplicationContext初始化方法把创建的XmlWebApplicationContext 塞到了 currentContextPerThread 中


说了一堆,跟Spring MVC 不配置ContextLoaderListener有什么关系呢。。。

因为 ContextLoaderListener 本质上是创建了一个 WebApplicationContext ,所以你的项目里面,如果不使用 WebApplicationContext 就可以不配置该节点。

那么只要做这种配置也是可以的:

[html]  view plain  copy
  1. <!-- Spring MVC -->  
  2.     <servlet>  
  3.         <servlet-name>teach</servlet-name>  
  4.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  5.         <init-param>  
  6.             <param-name>contextConfigLocation</param-name>  
  7.             <param-value>/WEB-INF/teach-servlet.xml</param-value>  
  8.         </init-param>  
  9.         <load-on-startup>1</load-on-startup>  
  10.     </servlet>  
  11.     <servlet-mapping>  
  12.         <servlet-name>teach</servlet-name>  
  13.         <url-pattern>*.action</url-pattern>  
  14.     </servlet-mapping>  

发现Spring MVC 所需的配置文件不使用context-param节点指定,直接在DispatcherServlet里面配置即可

注意:这种情况下,你的应用程序是无法使用WebApplicationContext的


正常情况下,都会配置ContextLoaderListener,因为我们知道Spring IOC的两种实现

基础的就是BeanFactory,高级的就是ApplicationContext,除非在资源非常有限的情况下,才使用BeanFactory

否则都使用ApplicationContext,而WebApplicationContext就是其中的一种高级实现,它能提供很多有用的方法


那么在应用程序如何获取 WebApplicationContext 呢,有多种方式,最简单的就是

[java]  view plain  copy
  1. WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();  

这个很熟悉了吧,刚才提到了,当前应用的WebApplicationContext就保存在 ContextLoader的currentContextPerThread属性当中


还有基于ServletContext上下文获取的方式

[java]  view plain  copy
  1. ServletContext sc = request.getSession().getServletContext();  
  2. ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);  
  3. ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(sc);  
  4. WebApplicationContext wac1 = (WebApplicationContext) sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  


还有一些更合适的,基于Spring提供的抽象类或者接口,在初始化Bean时注入ApplicationContext

继承自抽象类ApplicationObjectSupport
说明:抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。
Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。

继承自抽象类WebApplicationObjectSupport
说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext

实现接口ApplicationContextAware
说明:实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。
Spring初始化时,会通过该方法将ApplicationContext对象注入。
  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值