Rol / Propósito de ContextLoaderListener en Spring?

169

Estoy aprendiendo Spring Framework que se está utilizando en mi proyecto. Encontré la entrada ContextLoaderListener en mi archivo web.xml . ¿Pero no pudo entender exactamente cómo ayuda a un desarrollador?

En la documentación oficial de ContextLoaderListener dice que es para iniciar WebApplicationContext . Con respecto a WebApplicationContext, los JavaDoc dicen:

Interfaz para proporcionar configuración para una aplicación web.


¿Pero no puedo entender lo que estoy logrando con ContextLoaderListener que internamente inicializa el WebApplicationContext ?

Según tengo entendido , ContextLoaderListener lee el archivo de configuración de Spring (con el valor dado contra contextConfigLocation en web.xml ), lo analiza y carga el bean singleton definido en ese archivo de configuración. De manera similar, cuando queremos cargar el prototipo de bean , usaremos el mismo contexto de aplicación web para cargarlo. Entonces, inicializamos la aplicación web con ContextLoaderListener para que podamos leer / analizar / validar el archivo de configuración de antemano y siempre que queramos inyectar dependencia podemos hacerlo inmediatamente sin demora. ¿Es correcto este entendimiento?

M. Sach
fuente
1
¿Alguien puede decirme la diferencia entre RequestContextListener y ContextLoaderListener
VdeX

Respuestas:

111

Su comprensión es correcta. Aquí ApplicationContextes donde viven tus frijoles de primavera. El propósito de la ContextLoaderListeneres doble:

  1. para vincular el ciclo de vida de la ApplicationContextcon el ciclo de vida de la ServletContexty

  2. para automatizar la creación de ApplicationContext, para que no tenga que escribir código explícito para crearlo, es una función conveniente.

Otra cosa conveniente acerca de esto ContextLoaderListeneres que crea WebApplicationContexty WebApplicationContextproporciona acceso a los beans ServletContextvía ServletContextAwarey al getServletContextmétodo.

fuentedelica
fuente
2
Tengo una duda con respecto a su segundo punto. Dijiste que ServletContextListener proporciona acceso a ServletContext. Pero, incluso si web.xml no tiene ServletContextListener, se puede acceder a ServletContext a través de WebApplicationContext (WebApplicationContext se debe conectar automáticamente). Entonces, ¿qué hace exactamente relacionado con ServletContext?
Sumit Desai
Crea el WebApplicationContext. De lo contrario, debería crearse manualmente.
sourcedelica
¿ ContextLoaderListenerimplementa un método de destrucción para destruir todos los beans cuando el contenedor web se cierra?
pregunta el
sí, lo hace cuando contextDestroyedse llama. Ver los documentos de la API.
sourcedelica
@sourcedelica Tengo una duda después de leer esto, he revisado mis aplicaciones web.xml. En mi archivo xml hay dos oyentes ContextLoaderListenery DispatcherServlet. Así que supongo que no hay necesidad de ambos, ¿es seguro eliminar ContextLoaderListenerpor qué estoy preguntando porque la aplicación está activa desde hace 7-8 meses? web.xml está aquí para su referencia.
Amogh
43

ContextLoaderListeneres opcional . Solo para hacer un punto aquí: puede iniciar una aplicación Spring sin configurarla ContextLoaderListener, solo un mínimo básico web.xmlconDispatcherServlet .

Así es como se vería:

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>

Cree un archivo llamado dispatcher-servlet.xmly guárdelo debajo WEB-INF. Como mencionamos index.jspen la lista de bienvenida, agregue este archivo debajo WEB-INF.

dispatcher-servlet.xml

En el dispatcher-servlet.xmldefine tus frijoles:

<?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>
Vikram
fuente
2
Si es opcional, ¿cuándo quieres usarlo? Parece que Spring Security requiere que use DelegatingFilterProxy.
David
66
Debe usarlo cuando desee colocar su archivo Servlet en su ubicación personalizada o con un nombre personalizado, en lugar del nombre predeterminado "[nombre-servlet] -servlet.xml" y la ruta en "Web-INF /"
Ramesh Karna
¿Es una buena idea definir bean en dispatcher-servlet.xml que applicationContext.xml?
Chetan Gole
8
Por lo general, es mejor distribuir los beans reflejando las capas de la arquitectura de su aplicación. Los beans para la capa de presentación (por ejemplo, controladores mvc) pueden estar en dispatcher-servlet.xml. Los beans que pertenecen a la capa de servicio deben definirse applicationContext.xml. No es una regla estricta, pero es una buena práctica lograr la separación de las preocupaciones.
Claudio Venturini
2
@Ramesh Karna No creo que sea necesario para el cambio de nombre y ubicación. Creo que es necesario cuando estamos inicializando múltiples servlets Dispatcher y todavía queremos que un contexto raíz sea compartido por todos los propios contextos DispaterServlets, entonces necesitamos usar ContextLoaderListener.
supernova
23

Para una aplicación Spring simple, no tiene que definir ContextLoaderListeneren su web.xml; puedes poner todos tus archivos de configuración de Spring en <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>

Para una aplicación Spring más compleja, donde tiene múltiples DispatcherServletdefinidos, puede tener los archivos de configuración comunes de Spring que comparten todos los DispatcherServletdefinidos en 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>

Solo tenga en cuenta que ContextLoaderListenerrealiza el trabajo de inicialización real para el contexto de la aplicación raíz .

Encontré que este artículo ayuda mucho: Spring MVC - Contexto de aplicación vs Contexto de aplicación web

xli
fuente
el artículo compartido aquí realmente garantiza una comprensión profunda de los conceptos
Priyank Thakkar
10

El blog, " Propósito de ContextLoaderListener - Spring MVC " da una muy buena explicación.

Según esto, los contextos de aplicación son jerárquicos y, por lo tanto, el contexto de DispatcherSerlvet se convierte en hijo del contexto de ContextLoaderListener. Debido a lo cual, la tecnología que se utiliza en la capa del controlador (Struts o Spring MVC) puede ser independiente del contexto raíz creado ContextLoaderListener.

Dileepa
fuente
Gracias por compartirlo amigo .. :)
Deepak Kumar
3

Cuando desee colocar su archivo Servlet en su ubicación personalizada o con un nombre personalizado, en lugar de la convención de nomenclatura [servletname]-servlet.xmly la ruta predeterminadas Web-INF/, puede usar ContextLoaderListener.

Amo de la mazmorra
fuente
3

ContextLoaderListner es un escucha de Servlet que carga todos los diferentes archivos de configuración (configuración de la capa de servicio, configuración de la capa de persistencia, etc.) en un contexto de aplicación de resorte único.

Esto ayuda a dividir las configuraciones de resorte en múltiples archivos XML.

Una vez que se cargan los archivos de contexto, Spring crea un objeto WebApplicationContext basado en la definición de bean y lo almacena en el ServletContext de su aplicación web.

Prashant_M
fuente
3

ingrese la descripción de la imagen aquíEste oyente Bootstrap es para iniciar y cerrar la raíz de Spring WebApplicationContext. Como una aplicación web puede tener múltiples servlets de despacho y cada uno tiene su propio contexto de aplicación que contiene controladores, resolución de vista, asignaciones de manejador, etc. contexto de aplicación creado por servlets de despachador).

El segundo uso de este oyente es cuando desea utilizar la seguridad de primavera.

rulhaniam
fuente
3

Contextos raíz e hijo Antes de seguir leyendo, comprenda que:

La primavera puede tener múltiples contextos a la vez. Uno de ellos será el contexto raíz, y todos los demás contextos serán contextos secundarios.

Todos los contextos secundarios pueden acceder a los beans definidos en el contexto raíz; pero lo contrario no es cierto. El contexto raíz no puede acceder a los contextos secundarios beans.

ApplicationContext:

applicationContext.xml es la configuración del contexto raíz para cada aplicación web. Spring carga el archivo applicationContext.xml y crea el ApplicationContext para toda la aplicación. Solo habrá un contexto de aplicación por aplicación web. Si no está declarando explícitamente el nombre del archivo de configuración de contexto en web.xml utilizando el parámetro contextConfigLocation, Spring buscará el applicationContext.xml en la carpeta WEB-INF y lanzará FileNotFoundException si no puede encontrar este archivo.

ContextLoaderListener Realiza el trabajo de inicialización real para el contexto de la aplicación raíz. Lee un parámetro de contexto "contextConfigLocation" y pasa su valor a la instancia de contexto, analizándolo en rutas de archivos potencialmente múltiples que pueden estar separadas por cualquier número de comas y espacios, por ejemplo, "WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml ". ContextLoaderListener es opcional. Solo para hacer un punto aquí: puede iniciar una aplicación Spring sin configurar ContextLoaderListener, solo un mínimo web.xml básico con DispatcherServlet.

DispatcherServlet DispatcherServlet es esencialmente un Servlet (extiende HttpServlet) cuyo propósito principal es manejar las solicitudes web entrantes que coinciden con el patrón de URL configurado. Se necesita un URI entrante y encuentra la combinación correcta de controlador y vista. Entonces es el controlador frontal.

Cuando define un DispatcherServlet en la configuración de primavera, proporciona un archivo XML con entradas de clases de controlador, asignaciones de vistas, etc. utilizando el atributo contextConfigLocation.

WebApplicationContext Además de ApplicationContext, puede haber múltiples WebApplicationContext en una sola aplicación web. En palabras simples, cada DispatcherServlet asociado con un solo WebApplicationContext. El archivo xxx-servlet.xml es específico del DispatcherServlet y una aplicación web puede tener más de un DispatcherServlet configurado para manejar las solicitudes. En tales escenarios, cada DispatcherServlet tendría un xxx-servlet.xml configurado por separado. Pero applicationContext.xml será común para todos los archivos de configuración de servlet. Spring cargará por defecto el archivo llamado "xxx-servlet.xml" de su carpeta web-INF webapps donde xxx es el nombre del servlet en web.xml. Si desea cambiar el nombre de ese nombre de archivo o cambiar la ubicación, agregue initi-param con contextConfigLocation como nombre de parámetro.

Comparación y relación entre ellos:

ContextLoaderListener vs DispatcherServlet

ContextLoaderListener crea el contexto de la aplicación raíz. Las entradas de DispatcherServlet crean un contexto de aplicación hijo por entrada de servlet. Los contextos secundarios pueden acceder a beans definidos en el contexto raíz. Los beans en el contexto raíz no pueden acceder a los beans en contextos secundarios (directamente). Todos los contextos se agregan a ServletContext. Puede acceder al contexto raíz utilizando la clase WebApplicationContextUtils.

Después de leer la documentación de Spring, lo siguiente es entender:

a) Los contextos de aplicación son jerárquicos y también lo son los WebApplicationContexts. Consulte la documentación aquí.

b) ContextLoaderListener crea un contexto de aplicación web raíz para la aplicación web y lo coloca en el contexto de Servlet. Este contexto se puede utilizar para cargar y descargar los beans gestionados por resorte independientemente de qué tecnología se esté utilizando en la capa del controlador (Struts o Spring MVC).

c) DispatcherServlet crea su propio WebApplicationContext y los manejadores / controladores / resolutores de vista son administrados por este contexto.

d) Cuando ContextLoaderListener se usa junto con DispatcherServlet, se crea un contexto de aplicación web raíz primero como se dijo anteriormente y DispatcherSerlvet también crea un contexto hijo y se adjunta al contexto de aplicación raíz. Consulte la documentación aquí.

Cuando estamos trabajando con Spring MVC y también estamos usando Spring en la capa de servicios, proporcionamos dos contextos de aplicación. El primero se configura con ContextLoaderListener y el otro con DispatcherServlet

En general, definirá todos los beans relacionados con MVC (controlador y vistas, etc.) en el contexto DispatcherServlet, y todos los beans transversales como seguridad, transacciones, servicios, etc. en el contexto raíz por ContextLoaderListener.

Consulte esto para obtener más detalles: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

siddharth nawani
fuente
2

Básicamente, puede aislar el contexto de la aplicación raíz y el contexto de la aplicación web utilizando ContextLoaderListner.

El archivo de configuración asignado con el parámetro de contexto se comportará como la configuración de contexto de la aplicación raíz. Y el archivo de configuración asignado con el servlet del despachador se comportará como el contexto de la aplicación web.

En cualquier aplicación web podemos tener múltiples servlets de despachador, por lo que múltiples contextos de aplicación web.

Pero en cualquier aplicación web podemos tener solo un contexto de aplicación raíz que se comparte con todos los contextos de aplicación web.

Deberíamos definir nuestros servicios, entidades, aspectos, etc. comunes en el contexto de la aplicación raíz. Y los controladores, interceptores, etc. están en el contexto relevante de la aplicación web.

Un ejemplo de web.xml es

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

Aquí la clase de configuración example.config.AppConfig se puede usar para configurar servicios, entidades, aspectos, etc. en el contexto de la aplicación raíz que se compartirá con todos los demás contextos de la aplicación web (por ejemplo, aquí tenemos dos clases de configuración del contexto de la aplicación web RestConfig y WebConfig)

PD: Aquí ContextLoaderListener es completamente opcional. Si no mencionamos ContextLoaderListener en web.xml aquí, AppConfig no funcionará. En ese caso, necesitamos configurar todos nuestros servicios y entidades en WebConfig y Rest Config.

Anil Agrawal
fuente
1

Le dará un punto de enlace para colocar el código que desea ejecutar en el tiempo de implementación de la aplicación web

Jigar Joshi
fuente
Jigar, en realidad esto es lo que estoy tratando de descubrir. ¿Cuál es la característica que proporciona la clase de cargador de contexto predeterminado en el momento de la implementación?
M Sach
Cambiar propiedades / archivos xml y dejar que se vuelvan a cargar en tiempo de
ejecución
1

Clase de escucha: escucha un evento (p. Ej., Inicio / apagado del servidor)

ContextLoaderListener -

  1. Escucha durante el inicio / apagado del servidor
  2. Toma los archivos de configuración de Spring como entrada y crea los beans según la configuración y los prepara (destruye el bean durante el apagado)
  3. Los archivos de configuración se pueden proporcionar así en web.xml

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

En el contexto de Spring Framework, el propósito de ContextLoaderListener es cargar los otros beans en su aplicación, como los componentes de nivel medio y nivel de datos que controlan el back-end de la aplicación.

Salahin Rocky
fuente
0

Su comprensión es correcta. Me pregunto por qué no ves ninguna ventaja en ContextLoaderListener. Por ejemplo, necesita construir una fábrica de sesiones (para administrar la base de datos). Esta operación puede llevar algo de tiempo, por lo que es mejor hacerlo al inicio. Por supuesto, puede hacerlo con servlets init u otra cosa, pero la ventaja del enfoque de Spring es que realiza la configuración sin escribir código.

evg
fuente
0

Si escribimos web.xml sin ContextLoaderListener, entonces no podemos dar el atletismo usando customAuthenticationProvider en seguridad de primavera. Debido a que DispatcherServelet es el contexto secundario de ContextLoaderListener, customAuthenticationProvider es la parte de parentContext que es ContextLoaderListener. Por lo tanto, el contexto primario no puede tener las dependencias del contexto secundario. Por lo tanto, se recomienda escribir spring-context.xml en contextparam en lugar de escribirlo en initparam.

SathishSakthi
fuente
0

Creo que su uso real se produce cuando desea tener más de un archivo de configuración o tiene un archivo xyz.xml en lugar de applicationcontext.xml, por ejemplo

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

Otro enfoque para ContextLoaderListener es usar ContextLoaderServlet como se muestra a continuación

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

usuario666
fuente