Rôle / objectif de ContextLoaderListener au printemps?

169

J'apprends Spring Framework qui est utilisé dans mon projet. J'ai trouvé l' entrée ContextLoaderListener dans mon fichier web.xml . Mais vous ne pouviez pas comprendre comment cela aide exactement un développeur?

Dans la documentation officielle de ContextLoaderListener, il est indiqué de démarrer WebApplicationContext . Concernant WebApplicationContext, les JavaDocs disent:

Interface pour fournir la configuration d'une application Web.


Mais je ne suis pas en mesure de comprendre ce que je fais avec ContextLoaderListener qui initialise en interne le WebApplicationContext ?

Selon ce que je comprends , ContextLoaderListener lit le fichier de configuration Spring (avec la valeur donnée par rapport à contextConfigLocation dans web.xml ), l'analyse et charge le bean singleton défini dans ce fichier de configuration. De même, lorsque nous voulons charger un bean prototype , nous utiliserons le même contexte d'application Web pour le charger. Nous initialisons donc l'application Web avec ContextLoaderListener afin de lire / analyser / valider le fichier de configuration à l'avance et chaque fois que nous voulons injecter une dépendance, nous pouvons le faire immédiatement sans aucun délai. Cette compréhension est-elle correcte?

M Sach
la source
1
Quelqu'un peut-il me faire savoir la différence entre RequestContextListener et ContextLoaderListener
VdeX

Réponses:

111

Votre compréhension est correcte. C'est ApplicationContextlà que vivent vos haricots de printemps. Le but du ContextLoaderListenerest double:

  1. pour lier le cycle de vie du ApplicationContextau cycle de vie du ServletContextet

  2. pour automatiser la création du ApplicationContext, afin que vous n'ayez pas à écrire de code explicite pour le créer - c'est une fonction pratique.

Une autre chose pratique à propos de l ' ContextLoaderListenerest qu'il crée un WebApplicationContextet WebApplicationContextdonne accès aux beans ServletContextvia ServletContextAwareet à la getServletContextméthode.

sourcedelica
la source
2
J'ai un doute sur votre deuxième point. Vous avez dit que ServletContextListener donne accès à ServletContext. Mais, même si web.xml n'a pas ServletContextListener, ServletContext est accessible via WebApplicationContext (WebApplicationContext doit être autowired). Alors, que fait-il exactement lié à ServletContext?
Sumit Desai
Il crée le WebApplicationContext. Sinon, il devra être créé manuellement.
sourcedelica
ne ContextLoaderListenermettre en œuvre une méthode destroy pour détruire tous les haricots lorsque le conteneur se ferme Web vers le bas?
asgs
oui - il le fait quand il contextDestroyedest appelé. Consultez la documentation de l'API.
sourcedelica
@sourcedelica J'ai un doute après avoir lu ceci, j'ai vérifié mes applications web.xml. Dans mon fichier xml, il y a deux écouteurs ContextLoaderListeneret DispatcherServlet. Donc, je suppose qu'il n'y a pas besoin des deux, est-il sûr de supprimer ContextLoaderListenerpourquoi je demande parce que l'application est en ligne depuis 7 à 8 mois. web.xml est pour votre référence.
Amogh
43

ContextLoaderListenerest facultatif . Juste pour faire un point ici: vous pouvez démarrer une application Spring sans jamais la configurer ContextLoaderListener, juste un minimum de base web.xmlavec DispatcherServlet.

Voici à quoi cela ressemblerait:

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>

Créez un fichier appelé dispatcher-servlet.xmlet stockez-le sous WEB-INF. Puisque nous l'avons mentionné index.jspdans la liste de bienvenue, ajoutez ce fichier sousWEB-INF .

dispatcher-servlet.xml

Dans la dispatcher-servlet.xmldéfinition de vos haricots:

<?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
la source
2
Si elle est facultative, quand voulez - vous voulez l'utiliser? Il semble que Spring Security l'oblige à utiliser DelegatingFilterProxy.
David
6
Vous devez l'utiliser lorsque vous souhaitez placer votre fichier Servlet dans votre emplacement personnalisé ou avec un nom personnalisé, plutôt que le nom par défaut "[servlet-name] -servlet.xml" et le chemin sous "Web-INF /"
Ramesh Karna
Est-ce une bonne idée de définir le bean dans dispatcher-servlet.xml plutôt que dans applicationContext.xml?
Chetan Gole
8
Il est généralement préférable de distribuer les beans en reflétant les couches de l'architecture de votre application. Les beans pour la couche de présentation (par exemple les contrôleurs mvc) peuvent être dans dispatcher-servlet.xml. Les beans appartenant à la couche de service doivent être définis applicationContext.xml. Ce n'est pas une règle stricte, mais c'est une bonne pratique pour parvenir à une séparation des préoccupations.
Claudio Venturini
2
@Ramesh Karna Je ne pense pas que ce soit nécessaire pour le changement de nom et d'emplacement. Je pense que c'est nécessaire lorsque nous initialisons plusieurs servlets Dispatcher et que nous voulons toujours qu'un contexte racine soit partagé par tous les contextes DispaterServlets, nous devons utiliser ContextLoaderListener.
supernova
23

Pour une application Spring simple, vous n'avez pas à définir ContextLoaderListenerdans votre web.xml; vous pouvez simplement mettre tous vos fichiers de configuration Spring dans <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>

Pour une application Spring plus complexe, où vous avez plusieurs DispatcherServletdéfinis, vous pouvez avoir les fichiers de configuration Spring communs qui sont partagés par tous les DispatcherServletdéfinis dans le 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>

Gardez simplement à l'esprit, ContextLoaderListenereffectue le travail d'initialisation réel pour le contexte de l'application racine .

J'ai trouvé que cet article aide beaucoup: Spring MVC - Contexte d'application vs contexte d'application Web

xli
la source
l'article partagé ici garantit vraiment une compréhension approfondie des concepts
Priyank Thakkar
10

Le blog, " Objectif de ContextLoaderListener - Spring MVC " donne une très bonne explication.

Selon lui, les contextes d'application sont hiérarchiques et par conséquent le contexte de DispatcherSerlvet devient l'enfant du contexte de ContextLoaderListener. Pour cette raison, la technologie utilisée dans la couche contrôleur (Struts ou Spring MVC) peut être indépendante du contexte racine créé par ContextLoaderListener.

Dileepa
la source
Merci de l'avoir partagé .. :)
Deepak Kumar
3

Lorsque vous souhaitez placer votre fichier Servlet dans votre emplacement personnalisé ou avec un nom personnalisé, plutôt que la convention de dénomination [servletname]-servlet.xmlet le chemin par défaut sous Web-INF/, vous pouvez utiliser ContextLoaderListener.

Maître du donjon
la source
3

ContextLoaderListner est un écouteur de servlet qui charge tous les différents fichiers de configuration (configuration de la couche de service, configuration de la couche de persistance, etc.) dans un contexte d'application à ressort unique.

Cela permet de répartir les configurations de ressorts sur plusieurs fichiers XML.

Une fois les fichiers de contexte chargés, Spring crée un objet WebApplicationContext basé sur la définition du bean et le stocke dans le ServletContext de votre application Web.

Prashant_M
la source
3

entrez la description de l'image iciCet écouteur Bootstrap doit démarrer et arrêter la racine de Spring WebApplicationContext . Comme une application Web peut avoir plusieurs servlet de répartiteur et chacun ayant son propre contexte d'application contenant des contrôleurs, un résolveur de vue, des mappages de gestionnaires, etc. contexte d'application créé par les servlets du dispatcher).

La deuxième utilisation de cet auditeur est lorsque vous souhaitez utiliser la sécurité à ressort.

rulhaniam
la source
3

Contexte racine et enfant Avant de poursuivre la lecture, veuillez comprendre que -

Spring peut avoir plusieurs contextes à la fois. L'un d'eux sera le contexte racine, et tous les autres contextes seront des contextes enfants.

Tous les contextes enfants peuvent accéder aux beans définis dans le contexte racine; mais le contraire n'est pas vrai. Le contexte racine ne peut pas accéder aux beans de contextes enfants.

ApplicationContext:

applicationContext.xml est la configuration du contexte racine pour chaque application Web. Spring charge le fichier applicationContext.xml et crée le ApplicationContext pour l'ensemble de l'application. Il n'y aura qu'un seul contexte d'application par application Web. Si vous ne déclarez pas explicitement le nom du fichier de configuration de contexte dans web.xml à l'aide du paramètre contextConfigLocation, Spring recherchera l'applicationContext.xml sous le dossier WEB-INF et lèvera FileNotFoundException s'il n'a pas pu trouver ce fichier.

ContextLoaderListener Effectue le travail d'initialisation réel pour le contexte d'application racine. Lit un paramètre de contexte «contextConfigLocation» et transmet sa valeur à l'instance de contexte, l'analysant en plusieurs chemins de fichiers potentiellement séparés par un nombre quelconque de virgules et d'espaces, par exemple «WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml ». ContextLoaderListener est facultatif. Juste pour faire un point ici: vous pouvez démarrer une application Spring sans jamais configurer ContextLoaderListener, juste un web.xml minimum de base avec DispatcherServlet.

DispatcherServlet DispatcherServlet est essentiellement un servlet (il étend HttpServlet) dont le but principal est de gérer les demandes Web entrantes correspondant au modèle d'URL configuré. Il prend un URI entrant et trouve la bonne combinaison de contrôleur et de vue. C'est donc le contrôleur frontal.

Lorsque vous définissez un DispatcherServlet dans la configuration Spring, vous fournissez un fichier XML avec des entrées de classes de contrôleur, des mappages de vues, etc. à l'aide de l'attribut contextConfigLocation.

WebApplicationContext Outre ApplicationContext, il peut y avoir plusieurs WebApplicationContext dans une seule application Web. En termes simples, chaque DispatcherServlet est associé à un seul WebApplicationContext. Le fichier xxx-servlet.xml est spécifique au DispatcherServlet et une application Web peut avoir plus d'un DispatcherServlet configuré pour gérer les demandes. Dans de tels scénarios, chaque DispatcherServlet aurait un xxx-servlet.xml distinct configuré. Mais, applicationContext.xml sera commun à tous les fichiers de configuration de servlet. Spring chargera par défaut le fichier nommé «xxx-servlet.xml» à partir du dossier WEB-INF de votre webapps où xxx est le nom du servlet dans web.xml. Si vous souhaitez changer le nom de ce nom de fichier ou changer l'emplacement, ajoutez initi-param avec contextConfigLocation comme nom de paramètre.

Comparaison et relation entre eux:

ContextLoaderListener et DispatcherServlet

ContextLoaderListener crée un contexte d'application racine. Les entrées DispatcherServlet créent un contexte d'application enfant par entrée de servlet. Les contextes enfants peuvent accéder aux beans définis dans le contexte racine. Les beans dans le contexte racine ne peuvent pas accéder aux beans dans les contextes enfants (directement). Tous les contextes sont ajoutés à ServletContext. Vous pouvez accéder au contexte racine à l'aide de la classe WebApplicationContextUtils.

Après avoir lu la documentation Spring, voici la compréhension:

a) Les contextes d'application sont hiérarchisés, tout comme les contextes d'application Web. Reportez-vous à la documentation ici.

b) ContextLoaderListener crée un contexte d'application Web racine pour l'application Web et le place dans ServletContext. Ce contexte peut être utilisé pour charger et décharger les beans gérés par Spring indépendamment de la technologie utilisée dans la couche contrôleur (Struts ou Spring MVC).

c) DispatcherServlet crée son propre WebApplicationContext et les gestionnaires / contrôleurs / résolveurs de vues sont gérés par ce contexte.

d) Lorsque ContextLoaderListener est utilisé en tandem avec DispatcherServlet, un contexte d'application Web racine est créé en premier comme indiqué précédemment et un contexte enfant est également créé par DispatcherSerlvet et est attaché au contexte d'application racine. Reportez-vous à la documentation ici.

Lorsque nous travaillons avec Spring MVC et que nous utilisons également Spring dans la couche de services, nous fournissons deux contextes d'application. Le premier est configuré avec ContextLoaderListener et l'autre avec DispatcherServlet

En règle générale, vous définirez tous les beans liés à MVC (contrôleur et vues, etc.) dans le contexte DispatcherServlet, et tous les beans transversaux tels que la sécurité, les transactions, les services, etc. au contexte racine par ContextLoaderListener.

Référez-vous à ceci pour plus de détails: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

siddharth nawani
la source
2

Fondamentalement, vous pouvez isoler votre contexte d'application racine et le contexte d'application Web à l'aide de ContextLoaderListner.

Le fichier de configuration mappé avec le paramètre de contexte se comportera comme une configuration de contexte d'application racine. Et le fichier de configuration mappé avec le servlet du répartiteur se comportera comme un contexte d'application Web.

Dans n'importe quelle application Web, nous pouvons avoir plusieurs servlets de répartiteur, donc plusieurs contextes d'application Web.

Mais dans toute application Web, nous pouvons n'avoir qu'un seul contexte d'application racine partagé avec tous les contextes d'application Web.

Nous devons définir nos services communs, entités, aspects, etc. dans le contexte de l'application racine. Et les contrôleurs, intercepteurs, etc. sont dans le contexte d'application Web pertinent.

Un exemple de web.xml est

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

Ici, la classe de configuration example.config.AppConfig peut être utilisée pour configurer des services, des entités, des aspects, etc. dans le contexte d'application racine qui sera partagé avec tous les autres contextes d'application Web (par exemple, nous avons ici deux classes de configuration de contexte d'application Web RestConfig et WebConfig)

PS: Ici, ContextLoaderListener est complètement optionnel. Si nous ne mentionnons pas ContextLoaderListener dans web.xml ici, AppConfig ne fonctionnera pas. Dans ce cas, nous devons configurer tous nos services et entités dans WebConfig et Rest Config.

Anil Agrawal
la source
1

Cela vous donnera un point d'accroche pour mettre du code que vous souhaitez exécuter au moment du déploiement de l'application Web

Jigar Joshi
la source
Jigar, en fait, c'est ce que j'essaie de découvrir. Quelle est la fonctionnalité fournie par la classe de chargeur de contexte par défaut au moment du déploiement?
M Sach
Modification des propriétés / fichiers xml et laissez-les être rechargés au moment de l'
exécution
1

Listener class - Écoute un événement (par exemple, démarrage / arrêt du serveur)

ContextLoaderListener -

  1. Écoute pendant le démarrage / l'arrêt du serveur
  2. Prend les fichiers de configuration Spring comme entrée et crée les beans selon la configuration et le prépare (détruit le bean lors de l'arrêt)
  3. Les fichiers de configuration peuvent être fournis comme ceci dans web.xml

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

Dans le contexte du framework Spring, l'objectif de ContextLoaderListener est de charger les autres beans de votre application, tels que les composants de niveau intermédiaire et de niveau données qui pilotent le back-end de l'application.

Salahin Rocky
la source
0

Votre compréhension est correcte. Je me demande pourquoi vous ne voyez aucun avantage dans ContextLoaderListener. Par exemple, vous devez créer une fabrique de session (pour gérer la base de données). Cette opération peut prendre un certain temps, il est donc préférable de la faire au démarrage. Bien sûr, vous pouvez le faire avec des servlets d'initialisation ou autre chose, mais l'avantage de l'approche de Spring est que vous effectuez la configuration sans écrire de code.

evg
la source
0

Si nous écrivons web.xml sans ContextLoaderListener, nous ne pouvons pas donner l'athuntication à l'aide de customAuthenticationProvider dans Spring Security. Étant donné que DispatcherServelet est le contexte enfant de ContextLoaderListener, customAuthenticationProvider est la partie de parentContext qui est ContextLoaderListener. Ainsi, le contexte parent ne peut pas avoir les dépendances du contexte enfant. Il est donc recommandé d'écrire spring-context.xml dans contextparam au lieu de l'écrire dans initparam.

SathishSakthi
la source
0

Je pense que son utilisation réelle vient lorsque vous voulez avoir plus d'un fichier de configuration ou que vous avez un fichier xyz.xml au lieu de applicationcontext.xml par exemple

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

Une autre approche de ContextLoaderListener consiste à utiliser ContextLoaderServlet comme ci-dessous

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

utilisateur666
la source