ContextLoaderListener及其上下文与DispatcherServlet的区别

ContextLoaderListener和DispatcherServlet都会在Web容器启动的时候加载一下bean配置. 区别在于:

  • DispatcherServlet一般会加载MVC相关的bean配置管理(如: ViewResolver, Controller, MultipartResolver, ExceptionHandler, etc.)
  • ContextLoaderListener一般会加载整个Spring容器相关的bean配置管理(如: Log, Service, Dao, PropertiesLoader, DataSource Bean, etc.)

DispatcherServlet默认使用WebApplicationContext作为父上下文,如果在自己context中找不到对应的bean,则会在父上下文(也就是ApplicationContext)中去找。这也解释了为什么我们可以在DispatcherServlet中获取到由ContextLoaderListener对应的ApplicationContext中的bean.

DispatcherServlet也可以配置自己的初始化参数,覆盖默认配置:

参数

描述

contextClass

实现WebApplicationContext接口的类,当前的servlet用它来创建上下文。如果这个参数没有指定, 默认使用XmlWebApplicationContext。

contextConfigLocation

传给上下文实例(由contextClass指定)的字符串,用来指定上下文的位置。这个字符串可以被分成多个字符串(使用逗号作为分隔符) 来支持多个上下文(在多上下文的情况下,如果同一个bean被定义两次,后面一个优先)。
默认为/WEB-INF/[server-name]-servlet.xml

namespace

WebApplicationContext命名空间。默认值是[server-name]-servlet。

如下:

  1. <servlet>  
  2.         <servlet-name>demo</servlet-name>  
  3.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  4.         <load-on-startup>1</load-on-startup>  
  5.         <init-param>  
  6.             <param-name>contextConfigLocation</param-name>  
  7.             <param-value>classpath:spring-servlet-config.xml</param-value>  
  8.         </init-param>  
  9. </servlet>  
  10. <servlet-mapping>  
  11.         <servlet-name>demo</servlet-name>  
  12.         <url-pattern>/</url-pattern>  
  13. </servlet-mapping>  
<servlet>
        <servlet-name>demo</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-servlet-config.xml</param-value>
        </init-param>
</servlet>
<servlet-mapping>
        <servlet-name>demo</servlet-name>
        <url-pattern>/</url-pattern>
</servlet-mapping>


值得注意的是, DispatcherServlet的上下文仅仅是Spring MVC的上下文, 而ContextLoaderListener的上下文则对整个Spring都有效. 一般Spring web项目中同时会使用这两种上下文. 


上下文创建完后会放在ServletContext对象中, 其中:

1) ContextLoaderListener加载的上下文放在ServletContext的key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性中;

2) DispatcherServlet加载的上下文在每次请求时会放一份在request对象的key为WEB_APPLICATION_CONTEXT_ATTRIBUTE属性中. 

因而两者的获取方式也不一样, 前者可以通过:

WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)或

WebApplicationContextUtils.getWebApplicationContext(servletContext)或

WebApplicationContextUtils.getWebApplicationContext(servletContext,attrname)方法来获取对应的applicationContext,


而后者则通过:

RequestContextUtils.getWebApplicationContext(request)或 

WebApplicationContextUtils.getWebApplicationContext(servletContext,attrname)方法来获取对应的applicationContext.

(注: 对于ContextLoaderListener加载的上下文, attrname即上面提到的WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE; 

而对于DispatcherServlet中的上下文则为FrameworkServlet.class.getName() + “.CONTEXT.” + getServletName())


通过上下文所在的属性可以看出,如果通过WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)来试图获取DispatcherServlet加载的applicationContext时, 就会抛出”No WebApplicationContext found: no ContextLoaderListener registered?”的异常.


注:本文部分转载自网络, 其中大多数参考了ContextLoaderListener和Spring MVC中的DispatcherServlet学习

父子两个WebApplicationContext带来的麻烦
父WebApplicationContext里的bean可以在不同的子WebApplicationContext里共享,而不同的子WebApplicationContext里的bean区不干扰。
但是实际上有会不少的问题:
如果开发者不知道Spring mvc里分有两个WebApplicationContext,导致各种重复构造bean,各种bean无法注入的问题。
有一些bean,比如全局的aop处理的类,如果先父WebApplicationContext里初始化了,那么子WebApplicationContext里的初始化的bean就没有处理到。如果在子WebApplicationContext里初始化,在父WebApplicationContext里的类就没有办法注入了。

细节:
1. 从DispatcherServlet和ContextLoaderListener的初始化过程可以看出,二者分别会生成一个WebApplicationContext,且以不同的attrName注册到web容器中
2. 根据web.xml的加载顺序,listener总是先于servlet进行加载,因此虽然DispatcherServlet和ContextLoaderListener的WebApplicationContext不同,但是ContextLoaderListener的WebApplicationContext总是DispatcherServlet的父ApplicationContext
3. 同一个web容器中,只允许存在一个ContextLoaderListener,但可以存在多个DispatcherServlet
4. 由于二者生成的WebApplicationContext不同,因而这两个WebApplicationContext会分别去加载它们的配置,生成不同的BeanFactory;获取Spring Bean时,会先从DispatcherServlet的WebApplicationContext中查找,若不存在再通过父ApplicationContext,即ContextLoaderListener的WebApplicationContext,进行查找
5. 若二者的配置文件对Bean的定义存在交叉(即二者的配置文件中都定义了相同class且相同beanName的bean),则两个WebApplicationContext中都会保存一份该bean,但实际调用中只会用到DispatcherServlet中的bean,ContextLoaderListener中的bean无法调用到,成为内存泄漏
6. DispatcherServlet除了与ContextLoaderListener一样,会加载用户配置的bean以外,还会自动加载与web mvc相关的spring bean,如RequestMapping、ViewResolver、ExceptionHandler等
7. 项目中使用spring框架有2种方式:
1)listener下的ContextLoaderListener 是一种引入方式,默认读取/WEB-INF/applicationContext.xml
2)若是spring-web项目,DispatcherServlet 也是一种引入方式,默认读取/WEB-INF/${servlet-name}-servlet.xml

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值