java - starter - Rol/Propósito de ContextLoaderListener en Spring?
spring-boot-starter-web (14)
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 correlacionado con el parámetro de contexto se comportará como la configuración del contexto de la aplicación raíz. Y el archivo config correlacionado con el servlet dispatcher se comportará como el contexto de la aplicación web.
En cualquier aplicación web, podemos tener múltiples servlets de despachadores, por lo que múltiples contextos de aplicaciones 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 aplicaciones web.
Deberíamos definir nuestros servicios, entidades, aspectos, etc. comunes en el contexto de la aplicación raíz. Y los controladores, interceptores, etc. se encuentran en un contexto de aplicación web relevante.
Una muestra 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í config class 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 aplicaciones web (por ejemplo, aquí tenemos dos clases de configuración de 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, debemos configurar todos nuestros servicios y entidades en WebConfig y Rest Config.
Estoy aprendiendo Spring Framework que se está utilizando en mi proyecto. Encontré la entrada ContextLoaderListener en mi archivo web.xml . ¿Pero no pude entender cómo ayuda exactamente a un desarrollador?
En la documentación oficial de ContextLoaderListener dice que es para iniciar WebApplicationContext . Con respecto a WebApplicationContext JavaDocs dice:
Interfaz para proporcionar configuración para una aplicación web.
Pero no puedo entender lo que estoy logrando con ContextLoaderListener que internamente inicializa WebApplicationContext ?
Según mi entender , 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 prototipos de frijoles , usaremos el mismo contexto de aplicación de aplicaciones para cargarlo. Por lo tanto, inicializamos la aplicación web con ContextLoaderListener para que podamos leer / analizar / validar el archivo de configuración por adelantado y cada vez que deseemos inyectar una dependencia podemos hacerlo inmediatamente sin demora. ¿Es este entendimiento correcto?
Clase de escucha: escucha en un evento (por ejemplo, inicio / apagado del servidor)
ContextLoaderListener -
- Escucha durante el arranque / apagado del servidor
- 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)
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>
ContextLoaderListner es un oyente 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 el contexto de la aplicación de primavera única.
Esto ayuda a dividir configuraciones de muelles en múltiples archivos XML.
Una vez que se cargan los archivos de contexto, Spring crea un objeto WebApplicationContext basado en la definición del bean y lo almacena en el ServletContext de su aplicación web.
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 para, 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 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>
Cuando desee colocar su archivo Servlet en su ubicación personalizada o con un nombre personalizado, en lugar de la convención de nomenclatura predeterminada [servletname]-servlet.xml
y la ruta en Web-INF/
, puede usar ContextLoaderListener
.
El blog, " Propósito de ContextLoaderListener - Spring MVC " da una muy buena explicación.
Según ella, Application-Contexts son jerárquicos y, por lo tanto, el contexto de DispatcherSerlvet se convierte en el elemento secundario del contexto de ContextLoaderListener. Debido a lo cual, la tecnología que se utiliza en la capa de controlador (Struts o Spring MVC) puede ser independiente del contexto raíz creado ContextLoaderListener.
En el contexto del propósito del marco de primavera de ContextLoaderListener es cargar los otros beans en su aplicación, como los componentes de nivel medio y nivel de datos que manejan la parte de atrás de la aplicación.
Le dará un punto de enganche para poner algún código que desee que se ejecute en el tiempo de implementación de la aplicación web.
Para una aplicación simple de Spring, no tiene que definir ContextLoaderListener
en su web.xml
; puedes simplemente 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 de Spring más compleja, donde tiene definido múltiples DispatcherServlet
, puede tener los archivos de configuración Spring comunes que comparten todos los DispatcherServlet
definidos 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 ContextLoaderListener
realiza el trabajo de inicialización real para el contexto de la aplicación raíz .
Encontré este artículo que me ayuda mucho: Spring MVC - Contexto de la aplicación vs contexto de la aplicación web
Si escribimos web.xml sin ContextLoaderListener, entonces no podemos dar la información usando customAuthenticationProvider en la seguridad de primavera. Como DispatcherServelet es el contexto secundario de ContextLoaderListener, customAuthenticationProvider es la parte de parentContext que es ContextLoaderListener. Entonces, el Contexto padre no puede tener las dependencias del contexto hijo. Por lo tanto, es una buena práctica escribir spring-context.xml en contextparam en lugar de escribirlo en el initparam.
Su comprensión es correcta. Me pregunto por qué no ve ninguna ventaja en ContextLoaderListener. Por ejemplo, necesita construir una fábrica de sesiones (para gestionar 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.
Este oyente de Bootstrap debe iniciar y cerrar el WebApplicationContext raíz de Spring. Como una aplicación web puede tener múltiples servlets de despachador y cada uno tiene su propio contexto de aplicación que contiene controladores, resolución de vista, asignaciones de manejador, etc. Pero es posible que desee tener beans de servicio, beans DAO en el contexto de la aplicación raíz y desea usarlos en todos los contextos de aplicaciones secundarias ( contexto de aplicación creado por los servlets de despachador).
El segundo uso de este oyente es cuando desea usar la seguridad de primavera.
ContextLoaderListener
es opcional . Solo para hacer un punto aquí: puedes arrancar una aplicación de Spring sin tener que configurar ContextLoaderListener
, solo un web.xml
mínimo básico con DispatcherServlet
.
Aquí está lo que 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.xml
y guárdelo en WEB-INF
. Como mencionamos index.jsp
en la lista de bienvenida, agregue este archivo en WEB-INF
.
dispatcher-servlet.xml
En el dispatcher-servlet.xml
defina sus beans:
<?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>
Su comprensión es correcta. ApplicationContext
es donde viven sus Spring beans. El propósito del ContextLoaderListener
es doble:
para vincular el ciclo de vida de
ApplicationContext
al ciclo de vida deServletContext
ypara automatizar la creación de
ApplicationContext
, para que no tenga que escribir código explícito para crearlo, es una función de conveniencia.
Otra ContextLoaderListener
del ContextLoaderListener
es que crea un WebApplicationContext
y WebApplicationContext
proporciona acceso al ServletContext
través de los beans ServletContextAware
y el método getServletContext
.