Роль / Назначение ContextLoaderListener в Spring?

169

Я изучаю Spring Framework, который используется в моем проекте. Я нашел запись ContextLoaderListener в моем файле web.xml . Но не могли бы понять, как именно это помогает разработчику?

В официальной документации ContextLoaderListener говорится, что он должен запускать WebApplicationContext . Относительно WebApplicationContext JavaDocs говорят:

Интерфейс для предоставления конфигурации для веб-приложения.


Но я не могу понять, чего я добиваюсь с помощью ContextLoaderListener, который внутренне инициализирует WebApplicationContext ?

Насколько я понимаю , ContextLoaderListener читает конфигурационный файл Spring (со значением, заданным для contextConfigLocation в web.xml ), анализирует его и загружает bean-компонент singleton, определенный в этом конфигурационном файле. Точно так же, когда мы хотим загрузить прототип bean , мы будем использовать тот же контекст веб-приложения, чтобы загрузить его. Таким образом, мы инициализируем веб-приложение с помощью ContextLoaderListener, чтобы заранее прочитать / проанализировать / проверить файл конфигурации, и всякий раз, когда мы хотим внедрить зависимость, мы можем сразу сделать это без каких-либо задержек. Это понимание правильно?

М Сач
источник
1
кто-нибудь может дать мне знать разницу между RequestContextListener и ContextLoaderListener
VdeX

Ответы:

111

Ваше понимание верно. Там ApplicationContext, где живут ваши весенние бобы. Цель ContextLoaderListenerсостоит из двух частей :

  1. привязать жизненный цикл ApplicationContextк жизненному циклу ServletContextи

  2. автоматизировать создание ApplicationContext, так что вам не нужно писать явный код для его создания - это удобная функция.

Еще одна удобная вещь о ContextLoaderListenerтом , что он создает WebApplicationContextи WebApplicationContextобеспечивает доступ к ServletContextчерез ServletContextAwareфасолью и getServletContextметод.

sourcedelica
источник
2
У меня есть сомнения относительно вашего второго пункта. Вы сказали, что ServletContextListener предоставляет доступ к ServletContext. Но даже если в web.xml нет ServletContextListener, к ServletContext можно получить доступ через WebApplicationContext (WebApplicationContext должен быть подключен автоматически). Итак, что именно это имеет отношение к ServletContext?
Сумит Десаи
Это создает WebApplicationContext. В противном случае это должно было бы быть создано вручную.
sourcedelica
это ContextLoaderListenerреализовать метод уничтожения , чтобы уничтожить все бобы , когда веб - контейнер закрывается вниз?
спрашивает
да - он делает это, когда contextDestroyedназывается. Смотрите документацию по API.
sourcedelica
@sourcedelica У меня есть одно сомнение, прочитав это, я проверил свои приложения web.xml. В моем XML-файле есть два слушателя ContextLoaderListenerи DispatcherServlet. Итак, я думаю, что нет необходимости в обоих, безопасно ли удалить, ContextLoaderListenerпочему я спрашиваю, потому что приложение живет 7-8 месяцев. web.xml здесь для вашей справки.
Amogh
43

ContextLoaderListenerявляется необязательным . Просто чтобы подчеркнуть: вы можете загрузить приложение Spring без какой-либо настройки ContextLoaderListener, просто базовый минимум web.xmlс DispatcherServlet.

Вот как это будет выглядеть:

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>

Создайте файл с именем dispatcher-servlet.xmlи сохраните его в WEB-INF. Поскольку мы упоминали index.jspв списке приветствий, добавьте этот файл в WEB-INF.

диспетчер-servlet.xml

В dispatcher-servlet.xmlопределять бобы:

<?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
Если это необязательно, когда вы захотите его использовать? Кажется, Spring Security требует, чтобы он использовал DelegatingFilterProxy.
Дэвид
6
Вы должны использовать его, когда хотите поместить свой файл сервлета в свое пользовательское местоположение или с пользовательским именем, а не именем по умолчанию «[servlet-name] -servlet.xml» и путем в «Web-INF /»
Рамеш Карна
Это хорошая идея, чтобы определить bean-компонент в dispatcher-servlet.xml, чем applicationContext.xml?
Четан Голе
8
Обычно лучше распределять компоненты, отражая уровни архитектуры вашего приложения. Бины для уровня представления (например, контроллеры mvc) могут находиться в dispatcher-servlet.xml. Бины, принадлежащие сервисному слою, должны быть определены applicationContext.xml. Это не строгое правило, но это хорошая практика для достижения разделения интересов.
Клаудио Вентурини
2
@ Рамеш Карна Я не думаю, что это нужно для смены имени и местоположения. Я думаю, что это необходимо, когда мы инициализируем несколько сервлетов Dispatcher и все еще хотим, чтобы контекст Root был общим для всех собственных контекстов DispaterServlets, тогда нам нужно использовать ContextLoaderListener.
сверхновая
23

Для простого приложения Spring вам не нужно определять ContextLoaderListenerв своем web.xml; Вы можете просто поместить все свои файлы конфигурации Spring в <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>

Для более сложного приложения Spring, где у вас есть несколько DispatcherServletопределенных, у вас могут быть общие файлы конфигурации Spring, которые совместно используются всеми DispatcherServletопределенными в 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>

Просто имейте в виду, ContextLoaderListenerвыполняет фактическую работу инициализации для контекста корневого приложения.

Я обнаружил, что эта статья очень помогает: Spring MVC - контекст приложения против контекста веб-приложения

XLI
источник
разделенная здесь статья действительно обеспечивает глубокое понимание концепций
Priyank Thakkar
10

Блог " Цель ContextLoaderListener - Spring MVC " дает очень хорошее объяснение.

Согласно этому, контексты приложения являются иерархическими и, следовательно, контекст DispatcherSerlvet становится потомком контекста ContextLoaderListener. Благодаря этому технология, используемая на уровне контроллера (Struts или Spring MVC), может не зависеть от корневого контекста, созданного ContextLoaderListener.

Dileepa
источник
Спасибо, что поделился этим, приятель .. :)
Дипак Кумар
3

Если вы хотите поместить свой файл сервлета в свое пользовательское местоположение или с пользовательским именем, а не в соглашение о присвоении имен [servletname]-servlet.xmlи путь по умолчанию Web-INF/, тогда вы можете использовать ContextLoaderListener.

Dungeon_master
источник
3

ContextLoaderListner - это прослушиватель сервлетов, который загружает все различные файлы конфигурации (конфигурация уровня обслуживания, конфигурация уровня персистентности и т. Д.) В единый контекст приложения Spring.

Это помогает разделить конфигурации Spring на несколько файлов XML.

Как только файлы контекста загружены, Spring создает объект WebApplicationContext на основе определения компонента и сохраняет его в ServletContext вашего веб-приложения.

Prashant_M
источник
3

введите описание изображения здесьЭтот слушатель Bootstrap предназначен для запуска и завершения работы корневого WebApplicationContext в Spring. Поскольку веб-приложение может иметь несколько сервлетов-диспетчеров, и каждый из них имеет свой собственный контекст приложения, содержащий контроллеры, преобразователь представления, сопоставления обработчиков и т. Д. Но вы можете захотеть иметь служебные компоненты, компоненты DAO в контексте корневого приложения и использовать их во всех дочерних контекстах приложения ( контекст приложения, созданный диспетчерскими сервлетами).

Второе использование этого слушателя, когда вы хотите использовать Spring Security.

rulhaniam
источник
3

Коренные и дочерние контексты Прежде чем читать дальше, пожалуйста, поймите, что -

Spring может иметь несколько контекстов одновременно. Одним из них будет корневой контекст, а все остальные контексты будут дочерними контекстами.

Все дочерние контексты могут получить доступ к bean-компонентам, определенным в корневом контексте; но обратное не верно. Корневой контекст не может получить доступ к дочерним контекстам bean.

ApplicationContext:

applicationContext.xml - это корневая контекстная конфигурация для каждого веб-приложения. Spring загружает файл applicationContext.xml и создает ApplicationContext для всего приложения. В каждом веб-приложении будет только один контекст приложения. Если вы явно не объявляете имя файла конфигурации контекста в файле web.xml с помощью параметра contextConfigLocation, Spring выполнит поиск applicationContext.xml в папке WEB-INF и сгенерирует исключение FileNotFoundException, если не удалось найти этот файл.

ContextLoaderListener Выполняет фактическую работу инициализации для контекста корневого приложения. Считывает контекстный параметр «contextConfigLocation» и передает его значение экземпляру контекста, анализируя его в потенциально множественных файловых путях, которые могут быть разделены любым количеством запятых и пробелов, например «WEB-INF / applicationContext1.xml, WEB-INF / applicationContext2.xml». ContextLoaderListener является необязательным. Просто чтобы подчеркнуть: вы можете загрузить приложение Spring без какой-либо настройки ContextLoaderListener, просто базовый минимум web.xml с DispatcherServlet.

DispatcherServlet DispatcherServlet по сути является сервлетом (он расширяет HttpServlet), основной целью которого является обработка входящих веб-запросов, соответствующих настроенному шаблону URL. Он принимает входящий URI и находит правильную комбинацию контроллера и вида. Так что это передний контроллер.

Когда вы определяете DispatcherServlet в весенней конфигурации, вы предоставляете XML-файл с записями классов контроллеров, отображений представлений и т. Д., Используя атрибут contextConfigLocation.

WebApplicationContext Помимо ApplicationContext, в одном веб-приложении может быть несколько WebApplicationContext. Проще говоря, каждый DispatcherServlet связан с одним WebApplicationContext. Файл xxx-servlet.xml специфичен для DispatcherServlet, и веб-приложение может иметь более одного DispatcherServlet, настроенного для обработки запросов. В таких сценариях для каждого DispatcherServlet будет настроен отдельный файл xxx-servlet.xml. Но applicationContext.xml будет общим для всех файлов конфигурации сервлета. Spring по умолчанию загрузит файл с именем «xxx-servlet.xml» из папки WEB-INF вашего веб-приложения, где xxx - это имя сервлета в web.xml. Если вы хотите изменить имя этого файла или изменить местоположение, добавьте initi-param с contextConfigLocation в качестве имени параметра.

Сравнение и связь между ними:

ContextLoaderListener против DispatcherServlet

ContextLoaderListener создает корневой контекст приложения. Записи DispatcherServlet создают один дочерний контекст приложения для каждой записи сервлета. Дочерние контексты могут обращаться к bean-компонентам, определенным в корневом контексте. Бины в корневом контексте не могут получить доступ к бинам в дочерних контекстах (напрямую). Все контексты добавляются в ServletContext. Вы можете получить доступ к корневому контексту, используя класс WebApplicationContextUtils.

После прочтения документации Spring, следующее понимание:

a) Контексты приложения являются иерархическими, как и WebApplicationContexts. Обратитесь к документации здесь.

b) ContextLoaderListener создает корневой контекст веб-приложения для веб-приложения и помещает его в ServletContext. Этот контекст может использоваться для загрузки и выгрузки bean-компонентов, управляемых пружиной, независимо от того, какая технология используется на уровне контроллера (Struts или Spring MVC).

c) DispatcherServlet создает свой собственный WebApplicationContext, и обработчики / контроллеры / view-resolvers управляются этим контекстом.

d) Когда ContextLoaderListener используется в тандеме с DispatcherServlet, сначала создается корневой контекст веб-приложения, как было сказано ранее, а дочерний контекст также создается DispatcherSerlvet и присоединяется к корневому контексту приложения. Обратитесь к документации здесь.

Когда мы работаем с Spring MVC и также используем Spring на уровне сервисов, мы предоставляем два контекста приложения. Первый настраивается с использованием ContextLoaderListener, а другой - с помощью DispatcherServlet.

Как правило, вы определяете все связанные с MVC компоненты (контроллер и представления и т. Д.) В контексте DispatcherServlet, а также все сквозные компоненты, такие как безопасность, транзакции, службы и т. Д., В корневом контексте с помощью ContextLoaderListener.

Обратитесь к этому для получения более подробной информации: https://siddharthnawani.blogspot.com/2019/10/contextloaderlistener-vs.html

Сиддхарт Навани
источник
2

По сути, вы можете изолировать контекст корневого приложения и контекст веб-приложения, используя ContextLoaderListner.

Файл конфигурации, сопоставленный с параметром контекста, будет действовать как конфигурация контекста корневого приложения. И файл конфигурации, сопоставленный с сервлетом диспетчера, будет вести себя как контекст веб-приложения.

В любом веб-приложении у нас может быть несколько сервлетов-диспетчеров, поэтому несколько контекстов веб-приложения.

Но в любом веб-приложении у нас может быть только один корневой контекст приложения, общий для всех контекстов веб-приложения.

Мы должны определить наши общие службы, сущности, аспекты и т. Д. В контексте корневого приложения. А контроллеры, перехватчики и т. Д. Находятся в соответствующем контексте веб-приложения.

Пример файла 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> 

Здесь класс конфигурации example.config.AppConfig может использоваться для настройки служб, объектов, аспектов и т. Д. В контексте корневого приложения, который будет использоваться всеми остальными контекстами веб-приложения (например, здесь у нас есть два класса конфигурации контекста веб-приложения RestConfig и WebConfig)

PS: Здесь ContextLoaderListener является полностью необязательным. Если мы не будем упоминать ContextLoaderListener в web.xml здесь, AppConfig не будет работать. В этом случае нам нужно настроить все наши сервисы и объекты в WebConfig и Rest Config.

Анил Агравал
источник
1

Это даст вам возможность поместить некоторый код, который вы хотите выполнить, во время развертывания веб-приложения.

Джигар Джоши
источник
Джигар, на самом деле это то, что я пытаюсь выяснить. Какую функцию предоставляет класс загрузчика контекста по умолчанию во время развертывания?
М Сач
Изменение свойств / XML-файлов и их перезагрузка без перезапуска сервера
vsingh
1

Класс слушателя - прослушивает событие (например, запуск / завершение работы сервера)

ContextLoaderListener -

  1. Прослушивает во время запуска / выключения сервера
  2. Принимает файлы конфигурации Spring в качестве входных данных и создает компоненты согласно конфигурации и готовит их (уничтожает компонент во время завершения работы)
  3. Файлы конфигурации могут быть предоставлены как это в web.xml

    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>  
bharanitharan
источник
1

В контексте Spring Framework целью ContextLoaderListener является загрузка других bean-компонентов в вашем приложении, таких как компоненты среднего уровня и уровня данных, которые управляют серверной частью приложения.

Салахин Рокки
источник
0

Ваше понимание верно. Интересно, почему вы не видите никаких преимуществ в ContextLoaderListener. Например, вам нужно построить фабрику сессий (для управления базой данных). Эта операция может занять некоторое время, поэтому лучше сделать это при запуске. Конечно, вы можете сделать это с помощью сервлетов init или чего-то еще, но преимущество подхода Spring состоит в том, что вы конфигурируете без написания кода.

EVG
источник
0

Если мы напишем web.xml без ContextLoaderListener, то мы не сможем дать аутентификацию, используя customAuthenticationProvider в весенней безопасности. Поскольку DispatcherServelet является дочерним контекстом ContextLoaderListener, customAuthenticationProvider является частью parentContext, который является ContextLoaderListener. Поэтому родительский контекст не может иметь зависимости дочернего контекста. И поэтому лучше всего написать spring-context.xml в contextparam вместо того, чтобы записывать его в initparam.

SathishSakthi
источник
0

Я считаю, что его реальное использование происходит, когда вы хотите иметь более одного конфигурационного файла или у вас есть файл xyz.xml вместо applicationcontext.xml для, например,

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

Другой подход к ContextLoaderListener заключается в использовании ContextLoaderServlet, как показано ниже

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

user666
источник