Rola / cel ContextLoaderListener na wiosnę?

169

Uczę się Spring Framework, który jest używany w moim projekcie. Znalazłem wpis ContextLoaderListener w moim pliku web.xml . Ale nie możesz dowiedzieć się, jak dokładnie pomaga to deweloperowi?

W oficjalnej dokumentacji ContextLoaderListener jest napisane, że należy uruchomić WebApplicationContext . Dotyczące WebApplicationContext Javadocs powiedzieć:

Interfejs umożliwiający konfigurację aplikacji internetowej.


Ale nie jestem w stanie zrozumieć, co mam na osiągnięcie z ContextLoaderListener który wewnętrznie inicjuje WebApplicationContext ?

Zgodnie z moim rozumieniem , ContextLoaderListener odczytuje plik konfiguracyjny Springa (z wartością podaną w kontekście contextConfigLocation w web.xml ), analizuje go i ładuje pojedynczy komponent bean zdefiniowany w tym pliku konfiguracyjnym. Podobnie, gdy chcemy załadować prototypowy bean , użyjemy tego samego kontekstu aplikacji internetowej, aby go załadować. Tak więc inicjalizujemy aplikację internetową za pomocą ContextLoaderListener , abyśmy z wyprzedzeniem przeczytali / przeanalizowali / zweryfikowali plik konfiguracyjny i za każdym razem, gdy chcemy wprowadzić zależność, możemy od razu to zrobić bez żadnych opóźnień. Czy to rozumienie jest prawidłowe?

M Sach
źródło
1
czy ktoś może dać mi znać różnicę między RequestContextListener i ContextLoaderListener
VdeX

Odpowiedzi:

111

Twoje rozumienie jest prawidłowe. ApplicationContextJest, gdy fasola Wiosna żyć. Cel ContextLoaderListenerjest dwojaki:

  1. aby powiązać cykl życia z ApplicationContextcyklem życia ServletContexti

  2. zautomatyzować tworzenie ApplicationContextpliku, więc nie musisz pisać jawnego kodu, aby go utworzyć - jest to wygodna funkcja.

Inną wygodną rzeczą ContextLoaderListenerjest to, że tworzy WebApplicationContexti WebApplicationContextzapewnia dostęp do fasoli ServletContextvia ServletContextAwarei getServletContextmetody.

sourcedelica
źródło
2
Mam wątpliwości co do twojej drugiej kwestii. Powiedziałeś, że ServletContextListener zapewnia dostęp do ServletContext. Ale nawet jeśli web.xml nie ma ServletContextListener, dostęp do ServletContext można uzyskać za pośrednictwem WebApplicationContext (WebApplicationContext ma być autowired). Więc co dokładnie robi w związku z ServletContext?
Sumit Desai
Tworzy WebApplicationContext. W przeciwnym razie musiałby zostać utworzony ręcznie.
sourcedelica
czy ContextLoaderListenerimplementuje metodę niszczenia, aby zniszczyć wszystkie ziarna po wyłączeniu kontenera WWW?
asgs
tak - robi to, gdy contextDestroyedjest wezwany. Zobacz dokumentację API.
sourcedelica,
@sourcedelica Mam jedną wątpliwość po przeczytaniu tego sprawdziłem swoje aplikacje web.xml. W moim pliku xml znajdują się dwa odbiorniki ContextLoaderListeneri DispatcherServlet. Więc myślę, że nie ma potrzeby obu, czy można bezpiecznie usunąć, ContextLoaderListenerdlaczego pytam, ponieważ aplikacja działa od 7-8 miesięcy. web.xml jest tutaj w celach informacyjnych.
Amogh,
43

ContextLoaderListenerjest opcjonalne . Dla przypomnienia: możesz uruchomić aplikację Spring bez konfigurowania ContextLoaderListener, wystarczy podstawowe minimum za web.xmlpomocą DispatcherServlet.

Oto jak by to wyglądało:

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>

Utwórz plik o nazwie dispatcher-servlet.xmli zapisz go pod WEB-INF. Ponieważ wspomnieliśmy index.jspna liście powitalnej, dodaj ten plik pod WEB-INF.

dispatcher-servlet.xml

W dispatcher-servlet.xmlokreśl swoje fasole:

<?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
źródło
2
Jeśli jest opcjonalny, kiedy chcesz go użyć? Wygląda na to, że Spring Security wymaga, aby używał metody DelegatingFilterProxy.
David
6
Musisz go użyć, jeśli chcesz umieścić plik serwletu w niestandardowej lokalizacji lub z niestandardową nazwą, zamiast domyślnej nazwy „[nazwa-serwletu] -servlet.xml” i ścieżki w „Web-INF /”
Ramesh Karna
Czy warto zdefiniować bean w pliku dispatcher-servlet.xml niż applicationContext.xml?
Chetan Gole
8
Zwykle lepiej jest rozprowadzać ziarna, odzwierciedlając warstwy architektury aplikacji. Fasole dla warstwy prezentacji (na przykład kontrolery mvc) mogą znajdować się w pliku dispatcher-servlet.xml. Fasole należące do warstwy usługowej należy zdefiniować applicationContext.xml. Nie jest to ścisła zasada, ale dobrą praktyką jest oddzielenie obaw.
Claudio Venturini
2
@Ramesh Karna Myślę, że nie jest to potrzebne do zmiany nazwy i lokalizacji. Myślę, że jest to potrzebne, gdy inicjujemy wiele serwletów Dispatcher i nadal chcemy, aby kontekst główny był współdzielony przez wszystkie własne serwlety DispaterServlets, a następnie musimy użyć ContextLoaderListener.
supernowa
23

W przypadku prostej aplikacji Spring nie musisz definiować ContextLoaderListenerw swoim web.xml; możesz po prostu umieścić wszystkie pliki konfiguracyjne Springa w <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>

W przypadku bardziej złożonej aplikacji Spring, w której jest wiele DispatcherServletzdefiniowanych, możesz mieć wspólne pliki konfiguracyjne Spring, które są współdzielone przez wszystkie DispatcherServletzdefiniowane w 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>

Pamiętaj tylko, że ContextLoaderListenerwykonuje rzeczywistą pracę inicjalizacyjną dla kontekstu aplikacji głównej .

Zauważyłem, że ten artykuł bardzo pomaga: Spring MVC - Kontekst aplikacji a kontekst aplikacji internetowej

xli
źródło
artykuł udostępniony tutaj naprawdę zapewnia głębokie zrozumienie koncepcji
Priyank Thakkar
10

Blog „ Cel użycia ContextLoaderListener - Spring MVC ” zawiera bardzo dobre wyjaśnienie.

Zgodnie z nią konteksty aplikacji są hierarchiczne, a zatem kontekst DispatcherSerlvet staje się elementem potomnym kontekstu ContextLoaderListener. Dzięki temu technologia zastosowana w warstwie kontrolera (Struts lub Spring MVC) może być niezależna od tworzonego kontekstu głównego ContextLoaderListener.

Dileepa
źródło
Dzięki za udostępnienie tego, kolego .. :)
Deepak Kumar
3

Jeśli chcesz umieścić plik serwletu w niestandardowej lokalizacji lub z niestandardową nazwą zamiast domyślnej konwencji nazewnictwa [servletname]-servlet.xmli ścieżki Web-INF/, możesz użyć ContextLoaderListener.

Mistrz lochu
źródło
3

ContextLoaderListner to nasłuchiwacz serwletów, który ładuje wszystkie różne pliki konfiguracyjne (konfiguracja warstwy usług, konfiguracja warstwy trwałości itp.) Do jednego kontekstu aplikacji sprężynowej.

Pomaga to podzielić konfiguracje sprężyn na wiele plików XML.

Po załadowaniu plików kontekstowych Spring tworzy obiekt WebApplicationContext w oparciu o definicję fasoli i przechowuje go w ServletContext Twojej aplikacji internetowej.

Prashant_M
źródło
3

wprowadź opis obrazu tutajTen odbiornik Bootstrap ma uruchamiać i zamykać WebApplicationContext roota Springa . Ponieważ aplikacja internetowa może mieć wiele serwletów rozsyłających, a każdy z nich ma swój własny kontekst aplikacji zawierający kontrolery, program rozpoznawania widoku, mapowania programów obsługi itp. Ale możesz chcieć mieć komponenty bean usługi, komponenty bean DAO w kontekście aplikacji root i chcieć używać ich we wszystkich kontekstach aplikacji potomnych ( kontekst aplikacji utworzony przez serwlety dyspozytorskie).

Drugie zastosowanie tego słuchacza jest wtedy, gdy chcesz użyć zabezpieczenia sprężynowego.

rulhaniam
źródło
3

Konteksty root i child Zanim zaczniesz czytać dalej, zrozum, że -

Wiosna może mieć jednocześnie wiele kontekstów. Jeden z nich będzie kontekstem głównym, a wszystkie inne konteksty będą kontekstami potomnymi.

Wszystkie konteksty potomne mają dostęp do komponentów bean zdefiniowanych w kontekście głównym; ale przeciwieństwo nie jest prawdą. Kontekst główny nie może uzyskać dostępu do komponentów bean kontekstów potomnych.

ApplicationContext:

applicationContext.xml to konfiguracja kontekstu głównego dla każdej aplikacji internetowej. Spring ładuje plik applicationContext.xml i tworzy ApplicationContext dla całej aplikacji. W każdej aplikacji internetowej będzie tylko jeden kontekst aplikacji. Jeśli nie zadeklarujesz jawnie nazwy pliku konfiguracji kontekstu w web.xml przy użyciu parametru contextConfigLocation, Spring wyszuka plik applicationContext.xml w folderze WEB-INF i wyrzuci wyjątek FileNotFoundException, jeśli nie może znaleźć tego pliku.

ContextLoaderListener Wykonuje rzeczywistą pracę inicjalizacyjną dla kontekstu aplikacji głównej. Odczytuje parametr kontekstu „contextConfigLocation” i przekazuje jego wartość do instancji kontekstu, analizując je na potencjalnie wiele ścieżek plików, które można oddzielić dowolną liczbą przecinków i spacji, np. „WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml ”. ContextLoaderListener jest opcjonalne. Dla przypomnienia: możesz uruchomić aplikację Spring bez konfigurowania ContextLoaderListener, wystarczy podstawowy minimalny plik web.xml z DispatcherServlet.

DispatcherServlet DispatcherServlet jest zasadniczo serwletem (stanowi rozszerzenie HttpServlet), którego głównym celem jest obsługa przychodzących żądań WWW zgodnych ze skonfigurowanym wzorcem adresu URL. Przyjmuje przychodzący identyfikator URI i znajduje właściwą kombinację kontrolera i widoku. Więc to jest przedni kontroler.

Podczas definiowania DispatcherServlet w konfiguracji sprężynowej, udostępniasz plik XML z wpisami klas kontrolerów, odwzorowaniami widoków itp. Za pomocą atrybutu contextConfigLocation.

WebApplicationContext Oprócz ApplicationContext w jednej aplikacji internetowej może istnieć wiele elementów WebApplicationContext. Krótko mówiąc, każdy DispatcherServlet powiązany z pojedynczym WebApplicationContext. Plik xxx-servlet.xml jest specyficzny dla serwletu DispatcherServlet, a aplikacja internetowa może mieć więcej niż jeden serwlet DispatcherServlet skonfigurowany do obsługi żądań. W takich scenariuszach każdy DispatcherServlet miałby skonfigurowany oddzielny xxx-servlet.xml. Jednak plik applicationContext.xml będzie wspólny dla wszystkich plików konfiguracyjnych serwletu. Spring domyślnie wczyta plik o nazwie „xxx-servlet.xml” z folderu WEB-INF aplikacji webowych, gdzie xxx to nazwa serwletu w web.xml. Jeśli chcesz zmienić nazwę tej nazwy pliku lub zmienić lokalizację, dodaj parametr inicjacji z wartością contextConfigLocation jako nazwę parametru.

Porównanie i relacja między nimi:

ContextLoaderListener vs DispatcherServlet

ContextLoaderListener tworzy kontekst aplikacji głównej. Pozycje DispatcherServlet tworzą jeden kontekst aplikacji podrzędnej dla każdego wpisu serwletu. Konteksty potomne mogą uzyskiwać dostęp do komponentów bean zdefiniowanych w kontekście głównym. Fasola w kontekście głównym nie może uzyskać dostępu do fasoli w kontekstach potomnych (bezpośrednio). Wszystkie konteksty są dodawane do ServletContext. Dostęp do kontekstu głównego można uzyskać za pomocą klasy WebApplicationContextUtils.

Po przeczytaniu dokumentacji Spring, rozumiem:

a) Konteksty aplikacji są hierarchiczne, podobnie jak WebApplicationContexts. Zapoznaj się z dokumentacją tutaj.

b) ContextLoaderListener tworzy główny kontekst aplikacji internetowej dla aplikacji internetowej i umieszcza go w ServletContext. Ten kontekst może być używany do ładowania i rozładowywania ziaren sterowanych sprężynami w zależności od technologii używanej w warstwie kontrolera (Struts lub Spring MVC).

c) DispatcherServlet tworzy swój własny WebApplicationContext, a programy obsługi / kontrolery / programy rozpoznające widok są zarządzane przez ten kontekst.

d) Gdy ContextLoaderListener jest używany w tandemie z DispatcherServlet, najpierw tworzony jest główny kontekst aplikacji WWW, jak wspomniano wcześniej, a także jest tworzony przez DispatcherSerlvet kontekst potomny i dołączany do głównego kontekstu aplikacji. Zapoznaj się z dokumentacją tutaj.

Kiedy pracujemy z Spring MVC i używamy Springa również w warstwie usług, udostępniamy dwa konteksty aplikacji. Pierwsza jest konfigurowana za pomocą ContextLoaderListener, a druga za pomocą DispatcherServlet

Ogólnie rzecz biorąc, zdefiniujesz wszystkie komponenty bean powiązane z MVC (kontroler i widoki itp.) W kontekście DispatcherServlet, a wszystkie komponenty bean przekrojowe, takie jak bezpieczeństwo, transakcje, usługi itp. W kontekście głównym, za pomocą ContextLoaderListener.

Więcej informacji znajdziesz tutaj: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

siddharth nawani
źródło
2

Zasadniczo możesz izolować kontekst aplikacji głównej i kontekst aplikacji internetowej za pomocą ContextLoaderListner.

Plik konfiguracyjny mapowany z parametrem kontekstu będzie zachowywał się jak konfiguracja kontekstu aplikacji głównej. Plik konfiguracyjny odwzorowany za pomocą serwletu dyspozytorskiego będzie zachowywał się jak kontekst aplikacji internetowej.

W dowolnej aplikacji internetowej możemy mieć wiele serwletów dyspozytorskich, a więc wiele kontekstów aplikacji internetowych.

Ale w każdej aplikacji internetowej możemy mieć tylko jeden główny kontekst aplikacji, który jest współdzielony ze wszystkimi kontekstami aplikacji internetowych.

Powinniśmy zdefiniować nasze wspólne usługi, jednostki, aspekty itp. W kontekście aplikacji root. Kontrolery, przechwytywacze itp. Są w odpowiednim kontekście aplikacji internetowej.

Przykładowy plik web.xml to

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

Tutaj klasa config example.config.AppConfig może być używana do konfigurowania usług, jednostek, aspektów itp. W kontekście aplikacji głównej, które będą współdzielone ze wszystkimi innymi kontekstami aplikacji internetowych (na przykład tutaj mamy dwie klasy konfiguracji kontekstu aplikacji internetowej RestConfig i WebConfig)

PS: Tutaj ContextLoaderListener jest całkowicie opcjonalny. Jeśli nie wspomnimy tutaj o ContextLoaderListener w web.xml, AppConfig nie będzie działać. W takim przypadku musimy skonfigurować wszystkie nasze usługi i jednostki w konsoli WebConfig i Rest Config.

Anil Agrawal
źródło
1

Daje ci punkt zaczepienia, aby umieścić kod, który chcesz wykonać w czasie wdrażania aplikacji internetowej

Jigar Joshi
źródło
Jigar, właściwie to właśnie próbuję się dowiedzieć. Jaką funkcję zapewnia domyślna klasa programu ładującego kontekst w czasie wdrażania?
M Sach,
Zmiana właściwości / plików xml i umożliwienie ich ponownego załadowania w czasie wykonywania bez ponownego uruchamiania serwera
vsingh
1

Klasa Listener - nasłuchuje zdarzenia (np. Uruchomienie / zamknięcie serwera)

ContextLoaderListener -

  1. Nasłuchuje podczas uruchamiania / zamykania serwera
  2. Pobiera pliki konfiguracyjne Springa jako dane wejściowe i tworzy ziarna zgodnie z konfiguracją i przygotowuje je (niszczy ziarno podczas wyłączania)
  3. Pliki konfiguracyjne mogą być dostarczane w ten sposób w pliku web.xml

    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>  
bharanitharan
źródło
1

W kontekście Spring Framework celem ContextLoaderListener jest załadowanie innych komponentów bean w aplikacji, takich jak komponenty warstwy środkowej i warstwy danych, które sterują zapleczem aplikacji.

Salahin Rocky
źródło
0

Twoje rozumienie jest prawidłowe. Zastanawiam się, dlaczego nie widzisz żadnych zalet w ContextLoaderListener. Na przykład musisz zbudować fabrykę sesji (aby zarządzać bazą danych). Ta operacja może zająć trochę czasu, więc lepiej zrobić to podczas uruchamiania. Oczywiście możesz to zrobić za pomocą serwletów init lub czegoś innego, ale zaletą podejścia Springa jest to, że konfigurujesz bez pisania kodu.

evg
źródło
0

Jeśli napiszemy web.xml bez ContextLoaderListener, nie możemy zapewnić atestacji przy użyciu customAuthenticationProvider w wiosennych zabezpieczeniach. Ponieważ DispatcherServelet jest kontekstem podrzędnym ContextLoaderListener, customAuthenticationProvider jest częścią parentContext, która jest ContextLoaderListener. Zatem kontekst nadrzędny nie może mieć zależności kontekstu potomnego. Dlatego najlepszą praktyką jest zapisywanie pliku spring-context.xml w contextparam zamiast zapisywać go w initparam.

SathishSakthi
źródło
0

Wierzę, że jego prawdziwe zastosowanie pojawia się, gdy chcesz mieć więcej niż jeden plik konfiguracyjny lub masz plik xyz.xml zamiast applicationcontext.xml, np.

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

Innym podejściem do ContextLoaderListener jest użycie ContextLoaderServlet, jak poniżej

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

user666
źródło