178

我正在学习我的项目中使用的Spring Framework 。我在web.xml文件中找到了 ContextLoaderListener条目。但无法弄清楚它究竟如何帮助开发人员?

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

为 Web 应用程序提供配置的接口。


但是我无法理解我使用ContextLoaderListener实现了什么,它在内部初始化了WebApplicationContext

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

4

15 回答 15

118

你的理解是正确的。这ApplicationContext是你的 Spring bean 所在的地方。的目的有ContextLoaderListener两个:

  1. 将 theApplicationContext的生命周期与ServletContextand的生命周期联系起来

  2. 自动创建ApplicationContext,因此您不必编写显式代码来创建它 - 这是一个方便的功能。

另一个方便的事情ContextLoaderListener是它创建一个WebApplicationContext并提供对ServletContextvia ServletContextAwarebean 和getServletContext方法的访问。

于 2012-08-05T14:50:05.853 回答
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.

调度程序-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>
于 2014-03-09T00:23:38.383 回答
24

对于一个简单的 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>

对于一个更复杂的 Spring 应用程序,您DispatcherServlet定义了多个,您可以拥有由所有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 – Application Context vs Web Application Context

于 2016-02-26T20:25:41.917 回答
10

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

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

于 2015-04-22T12:50:13.963 回答
6

根上下文和子上下文 在进一步阅读之前,请理解——</p>

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

所有子上下文都可以访问根上下文中定义的bean;但相反是不正确的。根上下文不能访问子上下文 bean。

应用上下文:

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 是可选的。在这里强调一点:您可以启动 Spring 应用程序而无需配置 ContextLoaderListener,只需使用 DispatcherServlet 的基本最小 web.xml。

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

当您在 spring 配置中定义 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 creates a root web-application-context for the web-application and puts it in the ServletContext. This context can be used to load and unload the spring-managed beans ir-respective of what technology is being used in the controller layer(Struts or Spring MVC).

c) DispatcherServlet creates its own WebApplicationContext and the handlers/controllers/view-resolvers are managed by this context.

d) When ContextLoaderListener is used in tandem with DispatcherServlet, a root web-application-context is created first as said earlier and a child-context is also created by DispatcherSerlvet and is attached to the root application-context. Refer documentation here.

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

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

有关更多详细信息,请参阅此内容: https ://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

于 2019-10-27T05:22:18.283 回答
3

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

这有助于跨多个 XML 文件拆分 spring 配置。

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

于 2016-06-30T11:41:48.763 回答
3

基本上,您可以使用 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 中配置我们所有的服务和实体。

于 2016-08-09T18:51:42.013 回答
3

在此处输入图像描述这个 Bootstrap 监听器是用来启动和关闭 Spring 的WebApplicationContext。由于 Web 应用程序可以有多个调度程序 servlet,并且每个都有自己的应用程序上下文,其中包含控制器、视图解析器、处理程序映射等但是您可能希望在根应用程序上下文中有服务 bean、DAO bean 并希望在所有子应用程序上下文中使用(由调度程序 servlet 创建的应用程序上下文)。

第二次使用这个监听器是当你想使用 spring security 时。

于 2017-10-21T19:05:57.440 回答
2

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

于 2016-05-25T16:55:53.170 回答
1

它会给你一个钩子点来放置一些你希望在 Web 应用程序部署时执行的代码

于 2012-08-05T09:32:08.267 回答
1

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

ContextLoaderListener -

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

    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>  
    
于 2015-11-12T07:01:54.223 回答
1

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

于 2016-08-10T14:50:09.437 回答
0

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

于 2012-08-05T09:40:43.973 回答
0

如果我们在没有 ContextLoaderListener 的情况下编写 web.xml,那么我们就不能在 spring security 中使用 customAuthenticationProvider 来进行验证。因为 DispatcherServelet 是 ContextLoaderListener 的子上下文,所以 customAuthenticationProvider 是 parentContext 的一部分,即 ContextLoaderListener。所以父上下文不能有子上下文的依赖。因此最好在 contextparam 中编写 spring-context.xml 而不是在 initparam 中编写它。

于 2014-05-30T07:15:10.693 回答
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>

于 2015-06-03T00:16:34.803 回答