Spring中ContextLoaderListener的角色/目的?


169

我正在学习在我的项目中使用的Spring Framework。我在web.xml文件中找到了 ContextLoaderListener条目。但是无法弄清楚它对开发人员有多大帮助吗?

ContextLoaderListener的官方文档中,它表示要启动WebApplicationContext。关于WebApplicationContext JavaDocs说:

提供Web应用程序配置的界面。


但是我无法理解使用ContextLoaderListener实现内部初始化WebApplicationContext的目标吗?

据我了解ContextLoaderListener 读取Spring配置文件(具有针对web.xml中的contextConfigLocation的值),对其进行解析并加载在该配置文件中定义的单例bean。同样,当我们要加载原型bean时,我们将使用相同的Web应用程序上下文来加载它。因此,我们使用ContextLoaderListener初始化了Web应用程序,以便我们提前读取/解析/验证配置文件,并且每当我们要注入依赖项时,我们都可以立即进行操作而不会产生任何延迟。这种理解正确吗?


1
谁能让我知道
RequestContextListener

Answers:


111

您的理解是正确的。该ApplicationContext是你的Spring beans住的地方。的目的ContextLoaderListener有两个:

  1. 将的生命ApplicationContext周期与ServletContext和的生命周期联系起来

  2. 可以自动创建ApplicationContext,因此您无需编写显式代码即可创建它-这是一项便捷功能。

关于的另一个方便之处ContextLoaderListener是,它创建了一个,WebApplicationContextWebApplicationContext提供了对ServletContextvia ServletContextAwarebean和getServletContext方法的访问。


2
我对你的第二点有疑问。您说ServletContextListener提供对ServletContext的访问。但是,即使web.xml没有ServletContextListener,也可以通过WebApplicationContext访问ServletContext(WebApplicationContext将自动装配)。那么,它与ServletContext到底有什么关系呢?
Sumit Desai 2013年

它创建了WebApplicationContext。否则,将需要手动创建它。
sourcedelica 2013年

ContextLoaderListenerWeb容器关闭时,是否实现销毁方法来销毁所有bean?
ass 2013年

是的-它在contextDestroyed被调用时会执行。请参阅API文档。
sourcedelica 2013年

@sourcedelica我在阅读本文后有一个疑问,我已经检查了我的申请web.xml。在我的xml文件中,有两个监听器ContextLoaderListenerDispatcherServlet。因此,我想两者都没有必要,是否可以安全地删除ContextLoaderListener我提出的要求,因为申请已存在7至8个月。web.xml在这里供您参考。
Amogh '04

43

ContextLoaderListener可选的。此处仅说明一点:您无需配置即可启动Spring应用程序ContextLoaderListener,只需web.xml进行以下操作即可DispatcherServlet

看起来像这样:

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
    id="WebApp_ID" 
    version="2.5">
  <display-name>Some Minimal Webapp</display-name>
  <welcome-file-list>   
    <welcome-file>index.jsp</welcome-file>    
  </welcome-file-list>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
      org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

创建一个名为的文件dispatcher-servlet.xml并将其存储在下WEB-INF。由于我们index.jsp在欢迎列表中提到过,因此请在添加此文件WEB-INF

dispatcher-servlet.xml

dispatcher-servlet.xml定义您的bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd     
        http://www.springframework.org/schema/context     
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="bean1">
      ...
    </bean>
    <bean id="bean2">
      ...
    </bean>         

    <context:component-scan base-package="com.example" />
    <!-- Import your other configuration files too -->
    <import resource="other-configs.xml"/>
    <import resource="some-other-config.xml"/>

    <!-- View Resolver -->
    <bean 
        id="viewResolver" 
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
      <property 
          name="viewClass" 
          value="org.springframework.web.servlet.view.JstlView" />
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
    </bean>
</beans>

2
如果是可选的,您什么时候要使用它?看来Spring Security要求它使用DelegatingFilterProxy。
大卫

6
要将Servlet文件放在自定义位置或使用自定义名称,而不是默认名称“ [servlet-name] -servlet.xml”和“ Web-INF /”下的路径时,必须使用它
Ramesh Karna

与applicationContext.xml相比,在dispatcher-servlet.xml中定义bean是个好主意吗?
Chetan Gole 2015年

8
通常,最好通过反映应用程序体系结构的各个层次来分布bean。表示层的Bean(例如mvc控制器)可以位于dispatcher-servlet.xml中。属于服务层的Bean应该定义为applicationContext.xml。这不是严格的规则,但是这是实现关注点分离的良好实践。
克劳迪奥·文图里尼

2
@Ramesh Karna我认为不需要更改名称和位置。我认为当我们初始化多个Dispatcher servlet并且仍然希望Root上下文由所有DispaterServlet自己的上下文共享时,这是必需的,那么我们需要使用ContextLoaderListener。
超新星

23

对于简单的Spring应用程序,您无需ContextLoaderListenerweb.xml;中定义。您只需将所有Spring配置文件放入<servlet>

<servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc-core-config.xml, classpath:spring/business-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

对于具有多个DispatcherServlet定义的更复杂的Spring应用程序,可以拥有由以下所有DispatcherServlet定义共享的通用Spring配置文件ContextLoaderListener

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/common-config.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
    <servlet-name>mvc1</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc1-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet>
    <servlet-name>mvc2</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc2-config.xmll</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

请记住,ContextLoaderListener应用程序上下文执行实际的初始化工作。

我发现本文有很大帮助: Spring MVC –应用程序上下文与Web应用程序上下文


此处分享的文章确实确保了对概念的深入理解
Priyank Thakkar

10

博客“ ContextLoaderListener的目的– Spring MVC ”给出了很好的解释。

根据它,应用程序上下文是分层的,因此DispatcherSerlvet的上下文成为ContextLoaderListener上下文的子级。因此,控制器层(Struts或Spring MVC)中使用的技术可以独立于根上下文创建的ContextLoaderListener。


感谢您与朋友分享。.:)
Deepak Kumar 2015年

3

如果要将Servlet文件放在自定义位置或使用自定义名称,而不是默认的命名约定[servletname]-servlet.xml和路径放在下面Web-INF/,则可以使用ContextLoaderListener


3

ContextLoaderListner是一个Servlet侦听器,它将所有不同的配置文件(服务层配置,持久层配置等)加载到单个spring应用程序上下文中。

这有助于将弹簧配置拆分为多个XML文件。

加载上下文文件后,Spring将根据bean定义创建一个WebApplicationContext对象,并将其存储在Web应用程序的ServletContext中。


3

在此处输入图片说明该Bootstrap侦听器用于启动和关闭Spring的根目录 WebApplicationContext。作为一个Web应用程序,可以有多个调度程序servlet,每个都有自己的应用程序上下文,其中包含控制器,视图解析器,处理程序映射等。但是您可能希望在根应用程序上下文中具有服务Bean,DAO Bean,并希望在所有子应用程序上下文中使用(由调度程序Servlet创建的应用程序上下文)。

当您想使用Spring Security时,此监听器的第二个用途。


3

根和子上下文在进一步阅读之前,请了解-

Spring一次可以有多个上下文。其中之一将是根上下文,而所有其他上下文将是子上下文。

所有子上下文都可以访问在根上下文中定义的Bean。但事实并非如此。根上下文无法访问子上下文Bean。

ApplicationContext:

applicationContext.xml是每个Web应用程序的根上下文配置。Spring加载applicationContext.xml文件并为整个应用程序创建ApplicationContext。每个Web应用程序只有一个应用程序上下文。如果没有使用contextConfigLocation参数在web.xml中明确声明上下文配置文件名,Spring将在WEB-INF文件夹下搜索applicationContext.xml,如果找不到该文件,则抛出FileNotFoundException。

ContextLoaderListener为根应用程序上下文执行实际的初始化工作。读取“ contextConfigLocation”上下文参数,并将其值传递给上下文实例,将其解析为可能由多个逗号和空格分隔的多个文件路径,例如“ WEB-INF / applicationContext1.xml,WEB-INF / applicationContext2.xml”。ContextLoaderListener是可选的。此处仅说明一点:您无需配置ContextLoaderListener即可启动Spring应用程序,而仅使用DispatcherServlet配置基本的最小web.xml。

DispatcherServlet DispatcherServlet本质上是Servlet(它扩展了HttpServlet),其主要目的是处理与配置的URL模式匹配的传入Web请求。它使用传入的URI并找到控制器和视图的正确组合。因此,它是前端控制器。

在春季配置中定义DispatcherServlet时,您可以使用contextConfigLocation属性为XML文件提供控制器类,视图映射等条目。

WebApplicationContext除ApplicationContext之外,单个Web应用程序中可以有多个WebApplicationContext。简单来说,每个DispatcherServlet与单个WebApplicationContext相关联。xxx-servlet.xml文件特定于DispatcherServlet,并且一个Web应用程序可以配置多个DispatcherServlet来处理请求。在这种情况下,每个DispatcherServlet都会配置一个单独的xxx-servlet.xml。但是,applicationContext.xml对于所有servlet配置文件都是通用的。默认情况下,Spring将从您的webapps WEB-INF文件夹中加载名为“ xxx-servlet.xml”的文件,其中xxx是web.xml中的servlet名称。如果要更改该文件名的名称或更改位置,请添加带有contextConfigLocation作为参数名称的initi-param。

它们之间的比较和关系:

ContextLoaderListener与DispatcherServlet

ContextLoaderListener创建根应用程序上下文。DispatcherServlet条目为每个Servlet条目创建一个子应用程序上下文。子上下文可以访问在根上下文中定义的bean。根上下文中的Bean无法(直接)访问子上下文中的Bean。所有上下文都添加到ServletContext中。您可以使用WebApplicationContextUtils类访问根上下文。

阅读了Spring文档之后,您将了解以下内容:

a)应用程序上下文是层次结构,WebApplicationContexts也是如此。请参阅此处的文档。

b)ContextLoaderListener为Web应用程序创建一个根Web应用程序上下文,并将其放在ServletContext中。无论在控制器层中使用哪种技术(Struts或Spring MVC),都可以使用此上下文加载和卸载Spring管理的bean。

c)DispatcherServlet创建自己的WebApplicationContext,并且处理程序/控制器/视图解析器由该上下文管理。

d)当ContextLoaderListener与DispatcherServlet一起使用时,首先创建一个根Web应用程序上下文,如先前所述,并且一个子上下文也由DispatcherSerlvet创建,并附加到根应用程序上下文。请参阅此处的文档。

当我们使用Spring MVC并在服务层中使用Spring时,我们提供了两个应用程序上下文。第一个使用ContextLoaderListener配置,另一个使用DispatcherServlet配置

通常,您将在DispatcherServlet上下文中定义所有与MVC相关的bean(控制器和视图等),并在ContextLoaderListener的根上下文中定义所有跨领域的bean,例如安全性,事务,服务等。

请参阅此以获取更多详细信息:https : //siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html


2

基本上,您可以使用ContextLoaderListner隔离根应用程序上下文和Web应用程序上下文。

使用上下文参数映射的配置文件将充当根应用程序上下文配置。与调度程序servlet映射的配置文件的行为将类似于Web应用程序上下文。

在任何Web应用程序中,我们可能都有多个调度程序Servlet,因此有多个Web应用程序上下文。

但是在任何Web应用程序中,我们可能只有一个与所有Web应用程序上下文共享的根应用程序上下文。

我们应该在根应用程序上下文中定义我们的公共服务,实体,方面等。控制器,拦截器等都在相关的Web应用程序上下文中。

一个示例web.xml是

<!-- language: xml -->
<web-app>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>example.config.AppConfig</param-value>
    </context-param>
    <servlet>
        <servlet-name>restEntryPoint</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.config.RestConfig</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>restEntryPoint</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>webEntryPoint</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>example.config.WebConfig</param-value>
        </init-param>       
        <load-on-startup>1</load-on-startup>
    </servlet>  
    <servlet-mapping>
        <servlet-name>webEntryPoint</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app> 

此处的配置类example.config.AppConfig可用于在根应用程序上下文中配置将与所有其他Web应用程序上下文共享的服务,实体,方面等(例如,这里我们有两个Web应用程序上下文配置类RestConfig和WebConfig)

PS:这里ContextLoaderListener是完全可选的。如果我们在这里不提及web.xml中的ContextLoaderListener,则AppConfig将无法工作。在这种情况下,我们需要在WebConfig和Rest Config中配置所有服务和实体。


1

它将为您提供一些希望在Web应用程序部署时执行的代码的便利点


Jigar,实际上这就是我要找出的。部署时默认的上下文加载器类提供了什么功能?
M Sach 2012年

更改属性/ xml文件,并允许它们在运行时重新加载而无需重新启动服务器
vsingh 2015年

1

侦听器类-侦听事件(例如,服务器启动/关闭)

ContextLoaderListener-

  1. 在服务器启动/关闭期间监听
  2. 将Spring配置文件作为输入,并根据配置创建Bean并使其准备就绪(在关闭期间销毁Bean)
  3. 可以在web.xml中像这样提供配置文件

    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>  

1

在spring框架的上下文中,ContextLoaderListener的用途是在应用程序中加载其他bean,例如驱动应用程序后端的中间层和数据层组件。


0

您的理解是正确的。我想知道为什么您在ContextLoaderListener中看不到任何优势。例如,您需要构建一个会话工厂(以管理数据库)。此操作可能需要一些时间,因此最好在启动时进行。当然,您可以使用init servlet或其他方法来执行此操作,但是Spring的方法的优点是无需编写代码即可进行配置。


0

如果我们在没有ContextLoaderListener的情况下编写web.xml,那么我们就无法在Spring安全性中使用customAuthenticationProvider来给出attunication。因为DispatcherServelet是ContextLoaderListener的子上下文,所以customAuthenticationProvider是parentContext的一部分,即ContextLoaderListener。因此,父上下文不能具有子上下文的依赖项。因此,最佳实践是在contextparam中编写spring-context.xml而不是在initparam中编写。


0

我相信当您想要拥有多个配置文件或者您拥有xyz.xml文件而不是applicationcontext.xml 时,它的真正用途就来了,例如

<context-param><param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/training-service.xml, /WEB-INF/training-data.xml</param-value> </context-param>

ContextLoaderListener的另一种方法是使用ContextLoaderServlet,如下所示

<servlet> <servlet-name>context</servlet-name> <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.