Spring 中 ContextLoaderListener 的作用/目的?

Posted

技术标签:

【中文标题】Spring 中 ContextLoaderListener 的作用/目的?【英文标题】:Role/Purpose of ContextLoaderListener in Spring? 【发布时间】:2012-08-02 15:50:37 【问题描述】:

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

ContextLoaderListener 的官方文档中说是启动WebApplicationContext。关于WebApplicationContextJavaDocs 说:

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

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

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

【问题讨论】:

谁能告诉我RequestContextListener和ContextLoaderListener的区别 【参考方案1】:

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

【讨论】:

Jigar,实际上这就是我想要找出的。什么是功能,默认上下文加载器类在部署时提供? 更改属性/xml文件并让它们在运行时重新加载而无需重新启动服务器【参考方案2】:

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

【讨论】:

【参考方案3】:

你的理解是正确的。 ApplicationContext 是 Spring bean 所在的位置。 ContextLoaderListener 的目的有两个:

    ApplicationContext 的生命周期与ServletContext 的生命周期联系起来,并且

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

ContextLoaderListener 的另一个方便之处在于它创建了一个WebApplicationContext,并通过ServletContextAware bean 和getServletContext 方法提供对ServletContext 的访问。

【讨论】:

我对你的第二点有疑问。您说 ServletContextListener 提供对 ServletContext 的访问。但是,即使 web.xml 没有 ServletContextListener,也可以通过 WebApplicationContext 访问 ServletContext(WebApplicationContext 是要自动装配的)。那么,它到底与 ServletContext 有什么关系呢? 它创建了WebApplicationContext。否则需要手动创建。 ContextLoaderListener 是否实现了一个 destroy 方法来在 web 容器关闭时销毁所有 bean? 是的 - 当contextDestroyed 被调用时它会这样做。请参阅 API 文档。 @sourcedelica 读完这篇文章后我有一个疑问,我检查了我的应用程序web.xml。在我的 xml 文件中有两个监听器 ContextLoaderListenerDispatcherServlet。所以我想两者都不需要,删除ContextLoaderListener 是否安全,为什么我要问,因为应用程序自 7-8 个月以来一直存在。 web.xml 是here 供您参考。【参考方案4】:

ContextLoaderListener可选的。在这里说明一点:您可以启动 Spring 应用程序而无需配置 ContextLoaderListener,只需基本的最低配置 web.xmlDispatcherServlet

这是它的样子:

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>

【讨论】:

如果它是可选的,您会在什么时候想要使用它?似乎 Spring Security 要求它使用 DelegatingFilterProxy。 当你想把你的 Servlet 文件放在你的自定义位置或自定义名称时,你必须使用它,而不是默认名称“[servlet-name]-servlet.xml”和“下的路径” Web-INF/" 在 dispatcher-servlet.xml 中定义 bean 比在 applicationContext.xml 中定义更好吗? 通常最好通过反映应用程序体系结构的层来分发bean。表示层的 Bean(例如 mvc 控制器)可以在 dispatcher-servlet.xml 中。属于服务层的 Bean 应该定义为 applicationContext.xml。这不是一个严格的规则,但它是实现关注点分离的好习惯。 @Ramesh Karna 我认为不需要更改名称和位置。我认为当我们初始化多个 Dispatcher servlet 并且仍然希望所有 DispaterServlets 自己的上下文共享一个根上下文时需要它,然后我们需要使用 ContextLoaderListener。【参考方案5】:

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

【讨论】:

【参考方案6】:

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

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

【讨论】:

感谢分享它的朋友.. :)【参考方案7】:

我相信当您想要拥有多个配置文件或者您拥有 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>

【讨论】:

【参考方案8】:

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

ContextLoaderListener -

    在服务器启动/关闭期间监听 将 Spring 配置文件作为输入,并根据配置创建 bean 并使其准备就绪(在关闭期间销毁 bean)

    配置文件可以像这样在web.xml中提供

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

【讨论】:

【参考方案9】:

对于一个简单的 Spring 应用程序,您不必在 web.xml 中定义 ContextLoaderListener;你可以把你所有的 Spring 配置文件放在&lt;servlet&gt;:

<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,您可以拥有由 ContextLoaderListener 中定义的所有 DispatcherServlet 共享的公共 Spring 配置文件:

<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>

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

我发现这篇文章很有帮助: Spring MVC – Application Context vs Web Application Context

【讨论】:

这里分享的文章确实保证了对概念的深刻理解【参考方案10】:

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

【讨论】:

【参考方案11】:

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

这有助于将 spring 配置拆分到多个 XML 文件中。

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

【讨论】:

【参考方案12】:

基本上,您可以使用 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 和网络配置)

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

【讨论】:

【参考方案13】:

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

【讨论】:

【参考方案14】:

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

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

【讨论】:

【参考方案15】:

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

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 vs DispatcherServlet

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

阅读Spring文档后,理解如下:

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

b) ContextLoaderListener 为 web 应用程序创建一个根 web-application-context 并将其放入 ServletContext。此上下文可用于加载和卸载 spring 管理的 bean,而与控制器层中使用的技术(Struts 或 Spring MVC)无关。

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

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

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

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

更多详情请参考: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

【讨论】:

以上是关于Spring 中 ContextLoaderListener 的作用/目的?的主要内容,如果未能解决你的问题,请参考以下文章

Maven项目下update maven后Eclipse报错:java.lang.ClassNotFoundException: ContextLoaderL

学习笔记——Spring管理第三方bean;Spring中Bean的作用域;Spring中Bean的生命周期;Spring中bean的后置处理器;Spring中自动装配

Spring 4 安全、MySQL、c3p0 连接。登录在 Spring 5 中有效,但在 Spring 4 中无效

Spring Day01 Spring 框架概述以及Spring中基于XML的IOC配置

学习笔记——Spring简介;Spring搭建步骤;Spring的特性;Spring中getBean三种方式;Spring中的标签

spring中 实体类在啥时候交给spring容器管理?