Ruolo / scopo di ContextLoaderListener in primavera?


169

Sto imparando Spring Framework che viene utilizzato nel mio progetto. Ho trovato la voce ContextLoaderListener nel mio file web.xml . Ma non sei riuscito a capire come aiuta esattamente uno sviluppatore?

Nella documentazione ufficiale di ContextLoaderListener afferma che è necessario avviare WebApplicationContext . Riguardo a WebApplicationContext JavaDocs dire:

Interfaccia per fornire la configurazione per un'applicazione Web.


Ma non riesco a capire cosa sto ottenendo con ContextLoaderListener che inizializza internamente WebApplicationContext ?

Secondo la mia comprensione , ContextLoaderListener legge il file di configurazione Spring (con il valore dato a contextConfigLocation in web.xml ), lo analizza e carica il bean singleton definito in quel file di configurazione. Allo stesso modo quando vogliamo caricare il bean prototipo , useremo lo stesso contesto di applicazione web per caricarlo. Quindi inizializziamo l'applicazione web con ContextLoaderListener in modo che leggiamo / analizziamo / convalidiamo il file di configurazione in anticipo e ogni volta che desideriamo iniettare dipendenza possiamo immediatamente farlo senza alcun ritardo. Questa comprensione è corretta?


1
qualcuno può farmi sapere la differenza tra RequestContextListener e ContextLoaderListener
VdeX

Risposte:


111

La tua comprensione è corretta. È qui che ApplicationContextvivono i tuoi fagiolini. Lo scopo di ContextLoaderListenerè duplice:

  1. legare il ciclo di vita di ApplicationContextal ciclo di vita di ServletContexte

  2. per automatizzare la creazione di ApplicationContext, in modo da non dover scrivere codice esplicito per crearlo - è una funzione di convenienza.

Un'altra cosa conveniente riguardo a ContextLoaderListenerè che crea un WebApplicationContexte WebApplicationContextfornisce accesso ai ServletContextvia ServletContextAwarebean e al getServletContextmetodo.


2
Ho un dubbio sul tuo secondo punto. Hai detto che ServletContextListener fornisce l'accesso a ServletContext. Tuttavia, anche se web.xml non ha ServletContextListener, è possibile accedere a ServletContext tramite WebApplicationContext (WebApplicationContext deve essere autowired). Quindi, cosa fa esattamente in relazione a ServletContext?
Sumit Desai,

Crea il WebApplicationContext. Altrimenti dovrebbe essere creato manualmente.
sourcedelica,

non ContextLoaderListenerimplementare un metodo di distruggere per distruggere tutti i fagioli quando le chiude contenitore web verso il basso?
chiede il

si - lo fa quando contextDestroyedviene chiamato. Vedi i documenti API.
sourcedelica,

@sourcedelica Ho un dubbio dopo aver letto questo ho controllato le mie domande web.xml. Nel mio file xml ci sono due listener ContextLoaderListenere DispatcherServlet. Quindi suppongo che non sia necessario per entrambi, è sicuro rimuovere ContextLoaderListenerperché sto chiedendo perché l'applicazione è attiva da 7-8 mesi. web.xml è qui per riferimento.
Amogh

43

ContextLoaderListenerè facoltativo . Giusto per fare un punto qui: è possibile avviare un'applicazione Spring senza mai configurare ContextLoaderListener, solo un minimo di base web.xmlcon DispatcherServlet.

Ecco come sarebbe:

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>

Creare un file chiamato dispatcher-servlet.xmle archiviarlo in WEB-INF. Dato che abbiamo menzionato index.jspnella lista di benvenuto, aggiungi questo file sotto WEB-INF.

dispatcher-servlet.xml

Nel dispatcher-servlet.xmldefinire i tuoi fagioli:

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

2
Se è facoltativa, quando vorresti desiderare di usarlo? Sembra che Spring Security richieda l'utilizzo di DelegatingFilterProxy.
David,

6
Devi usarlo quando vuoi mettere il tuo file Servlet nella tua posizione personalizzata o con un nome personalizzato, piuttosto che il nome predefinito "[servlet-name] -servlet.xml" e il percorso in "Web-INF /"
Ramesh Karna

È una buona idea definire il bean in dispatcher-servlet.xml rispetto a applicationContext.xml?
Chetan Gole,

8
Di solito è meglio distribuire i bean riflettendo i livelli dell'architettura dell'applicazione. I bean per il livello di presentazione (ad esempio i controller mvc) possono essere in dispatcher-servlet.xml. I bean appartenenti al livello di servizio devono essere definiti applicationContext.xml. Non è una regola rigorosa, ma è una buona pratica ottenere la separazione delle preoccupazioni.
Claudio Venturini,

2
@Ramesh Karna Non credo sia necessario per il cambio di nome e posizione. Penso che sia necessario quando inizializziamo più servlet Dispatcher e vogliamo ancora che un contesto Root sia condiviso da tutti i contesti DispaterServlet, quindi dobbiamo usare ContextLoaderListener.
supernova,

23

Per una semplice applicazione Spring, non è necessario definire ContextLoaderListenernel proprio web.xml; puoi semplicemente inserire tutti i tuoi file di configurazione di Spring in <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>

Per un'applicazione Spring più complessa, dove ne sono stati DispatcherServletdefiniti più , è possibile avere i file di configurazione Spring comuni che sono condivisi da tutti i DispatcherServletdefiniti in 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>

Basta tenere a mente, ContextLoaderListeneresegue l'effettivo lavoro di inizializzazione per il root contesto dell'applicazione .

Ho trovato questo articolo molto utile: Spring MVC - Contesto dell'applicazione vs Contesto dell'applicazione Web


l'articolo condiviso qui garantisce davvero una profonda comprensione dei concetti
Priyank Thakkar il

10

Il blog " Scopo di ContextLoaderListener - Spring MVC " offre un'ottima spiegazione.

Secondo esso, i contesti applicativi sono gerarchici e quindi il contesto di DispatcherSerlvet diventa figlio del contesto ContextLoaderListener. A causa di ciò, la tecnologia utilizzata nel livello del controller (Struts o Spring MVC) può essere indipendente dal contesto root creato ContextLoaderListener.


Grazie per averlo condiviso amico .. :)
Deepak Kumar,

3

Quando vuoi mettere il tuo file Servlet nella tua posizione personalizzata o con un nome personalizzato, piuttosto che sotto la convenzione di denominazione [servletname]-servlet.xmle il percorso predefiniti Web-INF/, puoi usare ContextLoaderListener.


3

ContextLoaderListner è un listener Servlet che carica tutti i diversi file di configurazione (configurazione del livello di servizio, configurazione del livello di persistenza, ecc.) In un contesto di applicazione a molla singola.

Questo aiuta a dividere le configurazioni di primavera su più file XML.

Una volta caricati i file di contesto, Spring crea un oggetto WebApplicationContext in base alla definizione del bean e lo memorizza nel ServletContext dell'applicazione Web.


3

inserisci qui la descrizione dell'immagineQuesto listener Bootstrap è per avviare e chiudere la radice di Spring WebApplicationContext. Poiché un'applicazione Web può disporre di più servlet di dispatcher e ognuno con il proprio contesto di applicazione contenente controller, risoluzione dei problemi, mappature dei gestori ecc. Tuttavia, è possibile che si desideri disporre di bean di servizio, bean DAO nel contesto dell'applicazione radice e utilizzare in tutto il contesto dell'applicazione figlio ( contesto dell'applicazione creato dai servlet del dispatcher).

Il secondo utilizzo di questo listener è quando si desidera utilizzare la sicurezza di primavera.


3

Contesti di root e child Prima di leggere oltre, ti preghiamo di comprendere che -

La primavera può avere più contesti alla volta. Uno di questi sarà il contesto radice e tutti gli altri contesti saranno contesti figlio.

Tutti i contesti figlio possono accedere ai bean definiti nel contesto radice; ma il contrario non è vero. Il contesto di root non può accedere ai bean di contesti figlio.

ApplicationContext:

applicationContext.xml è la configurazione del contesto radice per ogni applicazione web. Spring carica il file applicationContext.xml e crea ApplicationContext per l'intera applicazione. Ci sarà un solo contesto applicativo per applicazione web. Se non stai dichiarando esplicitamente il nome del file di configurazione del contesto in web.xml usando il parametro contextConfigLocation, Spring cercherà applicationContext.xml nella cartella WEB-INF e genererà FileNotFoundException se non è stato possibile trovare questo file.

ContextLoaderListener Esegue il lavoro di inizializzazione effettivo per il contesto dell'applicazione root. Legge un parametro di contesto "contextConfigLocation" e passa il suo valore all'istanza di contesto, analizzandolo in percorsi di file potenzialmente multipli che possono essere separati da un numero qualsiasi di virgole e spazi, ad esempio "WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml”. ContextLoaderListener è facoltativo. Giusto per fare un punto qui: puoi avviare un'applicazione Spring senza mai configurare ContextLoaderListener, solo un web.xml minimo di base con DispatcherServlet.

DispatcherServlet DispatcherServlet è essenzialmente un Servlet (estende HttpServlet) il cui scopo principale è gestire le richieste Web in entrata corrispondenti al modello URL configurato. Prende un URI in entrata e trova la giusta combinazione di controller e vista. Quindi è il front controller.

Quando si definisce un DispatcherServlet nella configurazione di primavera, si fornisce un file XML con voci di classi di controller, mappature di viste ecc. Utilizzando l'attributo contextConfigLocation.

WebApplicationContext Oltre a ApplicationContext, possono esserci più WebApplicationContext in una singola applicazione Web. In parole semplici, ogni DispatcherServlet associato al singolo WebApplicationContext. Il file xxx-servlet.xml è specifico di DispatcherServlet e un'applicazione Web può avere più di un DispatcherServlet configurato per gestire le richieste. In tali scenari, ogni DispatcherServlet avrebbe configurato un xxx-servlet.xml separato. Ma applicationContext.xml sarà comune per tutti i file di configurazione del servlet. Per impostazione predefinita, Spring caricherà il file denominato "xxx-servlet.xml" dalla cartella WEB-INF di webapps dove xxx è il nome servlet in web.xml. Se si desidera modificare il nome di quel nome file o modificare la posizione, aggiungere initi-param con contextConfigLocation come nome param.

Confronto e relazione tra loro:

ContextLoaderListener vs DispatcherServlet

ContextLoaderListener crea il contesto dell'applicazione root. Le voci DispatcherServlet creano un contesto di applicazione figlio per voce servlet. I contesti secondari possono accedere ai bean definiti nel contesto principale. I bean nel contesto radice non possono accedere ai bean nei contesti figlio (direttamente). Tutti i contesti vengono aggiunti a ServletContext. È possibile accedere al contesto principale utilizzando la classe WebApplicationContextUtils.

Dopo aver letto la documentazione di primavera, la seguente è la comprensione:

a) I contesti applicativi sono gerarchici, così come i contesti WebApplication. Consultare la documentazione qui.

b) ContextLoaderListener crea un contesto di applicazione Web radice per l'applicazione Web e lo inserisce in ServletContext. Questo contesto può essere utilizzato per caricare e scaricare i bean gestiti a molla indipendentemente dalla tecnologia utilizzata nel livello del controller (Struts o Spring MVC).

c) DispatcherServlet crea il proprio WebApplicationContext e i gestori / controller / risolutore di viste sono gestiti da questo contesto.

d) Quando ContextLoaderListener viene utilizzato in tandem con DispatcherServlet, un contesto di applicazione Web radice viene creato prima come detto in precedenza e un contesto figlio viene creato da DispatcherSerlvet ed è collegato al contesto di applicazione radice. Consultare la documentazione qui.

Quando lavoriamo con Spring MVC e utilizziamo anche Spring nel livello dei servizi, forniamo due contesti applicativi. Il primo è configurato utilizzando ContextLoaderListener e l'altro con DispatcherServlet

Generalmente, verranno definiti tutti i bean correlati a MVC (controller e viste, ecc.) Nel contesto DispatcherServlet e tutti i bean trasversali come sicurezza, transazione, servizi ecc. Nel contesto di root tramite ContextLoaderListener.

Fare riferimento a questo per maggiori dettagli: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html


2

Fondamentalmente è possibile isolare il contesto dell'applicazione radice e il contesto dell'applicazione Web utilizzando ContextLoaderListner.

Il file di configurazione mappato con il parametro di contesto si comporterà come configurazione del contesto dell'applicazione radice. E il file di configurazione mappato con il servlet dispatcher si comporterà come il contesto dell'applicazione web.

In qualsiasi applicazione web potremmo avere più servlet di dispatcher, quindi più contesti di applicazioni web.

Ma in qualsiasi applicazione web potremmo avere un solo contesto di applicazione root condiviso con tutti i contesti dell'applicazione web.

Dovremmo definire i nostri servizi, entità, aspetti comuni ecc. Nel contesto dell'applicazione radice. E controller, intercettori ecc. Si trovano nel contesto pertinente dell'applicazione web.

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

Qui la classe di configurazione esempio.config.AppConfig può essere utilizzata per configurare servizi, entità, aspetti ecc. Nel contesto dell'applicazione radice che verrà condiviso con tutti gli altri contesti dell'applicazione Web (ad esempio qui abbiamo due classi di configurazione del contesto dell'applicazione Web RestConfig e WebConfig)

PS: qui ContextLoaderListener è completamente opzionale. Se non menzioneremo ContextLoaderListener in web.xml qui, AppConfig non funzionerà. In tal caso, dobbiamo configurare tutti i nostri servizi ed entità in WebConfig e Rest Config.


1

Ti consentirà di inserire un po 'di codice che desideri eseguire al momento della distribuzione dell'applicazione web


Jigar, in realtà questo è quello che sto cercando di scoprire. Qual è la funzionalità, la classe caricatore di contesto predefinito fornisce al momento della distribuzione?
M Sach,

Modifica dei file proprietà / xml e consenti loro di ricaricarli in fase di runtime senza riavviare il server
vsingh

1

Classe listener: ascolta un evento (ad es. Avvio / arresto del server)

ContextLoaderListener -

  1. Ascolta durante l'avvio / l'arresto del server
  2. Prende i file di configurazione di Spring come input e crea i bean secondo la configurazione e li rende pronti (distrugge il bean durante l'arresto)
  3. I file di configurazione possono essere forniti in questo modo in web.xml

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

1

Nel contesto dello scopo del framework di primavera di ContextLoaderListener è caricare gli altri bean nell'applicazione, ad esempio i componenti di livello intermedio e di livello dati che guidano il back-end dell'applicazione.


0

La tua comprensione è corretta. Mi chiedo perché non vedi alcun vantaggio in ContextLoaderListener. Ad esempio, è necessario creare un factory di sessione (per gestire il database). Questa operazione può richiedere del tempo, quindi è meglio farlo all'avvio. Ovviamente puoi farlo con i servlet init o qualcos'altro, ma il vantaggio dell'approccio di Spring è che fai la configurazione senza scrivere codice.


0

Se scriviamo web.xml senza ContextLoaderListener, allora non possiamo dare l'aspettativa usando customAuthenticationProvider nella sicurezza primaverile. Poiché DispatcherServelet è il contesto figlio di ContextLoaderListener, customAuthenticationProvider è la parte di parentContext che è ContextLoaderListener. Quindi il contesto padre non può avere le dipendenze del contesto figlio. E quindi è consigliabile scrivere spring-context.xml in contextparam invece di scriverlo in initparam.


0

Credo che il suo vero utilizzo arrivi quando vuoi avere più di un file di configurazione o hai un file xyz.xml invece di applicationcontext.xml per es.

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

Un altro approccio a ContextLoaderListener è l'utilizzo di ContextLoaderServlet come di seguito

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.