ChatGPT解决这个技术问题 Extra ChatGPT

Spring 中 ContextLoaderListener 的作用/目的?

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

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

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

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

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

谁能让我知道 RequestContextListener 和 ContextLoaderListener 之间的区别

s
sathishs4r

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

将 ApplicationContext 的生命周期与 ServletContext 的生命周期联系起来并自动创建 ApplicationContext,因此您不必编写显式代码来创建它 - 这是一个方便的功能。

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


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

ContextLoaderListener可选的。在此强调一点:您无需配置 ContextLoaderListener 即可启动 Spring 应用程序,只需基本的最低配置 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 下。

调度程序-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。表示层的 Bean(例如 mvc 控制器)可以在 dispatcher-servlet.xml 中。属于服务层的 Bean 应该定义为 applicationContext.xml。这不是一个严格的规则,但它是实现关注点分离的好习惯。
@Ramesh Karna 我认为不需要更改名称和位置。我认为当我们初始化多个 Dispatcher servlet 并且仍然希望所有 DispaterServlets 自己的上下文共享一个根上下文时需要它,然后我们需要使用 ContextLoaderListener。
x
xli

对于简单的 Spring 应用程序,您不必在 web.xml 中定义 ContextLoaderListener;您可以将所有 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 应用程序,您可以拥有由 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


这里分享的文章确实确保了对概念的深刻理解
D
Dileepa

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

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


谢谢你分享它哥们.. :)
s
siddharth nawani

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

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


P
Prashant_M

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

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

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


A
Anil Agrawal

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


r
rulhaniam

https://i.stack.imgur.com/hiv9t.gif

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


A
Ajeet Shah

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


j
jmj

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


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

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

ContextLoaderListener -

在服务器启动/关闭期间监听 将 Spring 配置文件作为输入,并根据配置创建 bean 并使其准备就绪(在关闭期间销毁 bean) 配置文件可以像这样在 web.xml contextConfigLocation< /param-name> /WEB-INF/dispatcher-servlet.xml


S
Salahin Rocky

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


e
evg

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


S
SathishSakthi

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


u
user666

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