ContextLoaderListener или нет?


122

Стандартное веб-приложение Spring (созданное Roo или шаблоном «Spring MVC Project») создает файл web.xml с помощью ContextLoaderListenerи DispatcherServlet. Почему они не только используют DispatcherServletи заставляют загружать полную конфигурацию?

Я понимаю, что ContextLoaderListener следует использовать для загрузки материалов, не относящихся к сети, а DispatcherServlet используется для загрузки материалов, относящихся к сети (контроллеры, ...). И это приводит к двум контекстам: родительскому и дочернему.

Задний план:

Я делал это стандартным образом несколько лет.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Handles Spring requests -->
<servlet>
    <servlet-name>roo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Это часто вызывало проблемы с двумя контекстами и зависимостями между ними. В прошлом мне всегда удавалось найти решение, и у меня есть сильное чувство, что это всегда улучшает структуру / архитектуру программного обеспечения. Но теперь я столкнулся с проблемой событий обоих контекстов .

- Однако это заставляет меня переосмыслить этот шаблон с двумя контекстами, и я спрашиваю себя: почему я должен ввязываться в эту проблему, почему бы не загрузить все файлы конфигурации Spring с одним DispatcherServletи ContextLoaderListenerполностью удалить файл . (У меня по-прежнему будут разные файлы конфигурации, но только один контекст.)

Есть ли причина не удалять ContextLoaderListener?


«Это часто вызывало проблемы с двумя контекстами и зависимостями между ними». Это отличный пример того, как, на мой взгляд, фреймворки для внедрения зависимостей просто усложняют нашу жизнь, чем самостоятельное внедрение зависимостей.
Энди

1
@Andy - Хотя я немного симпатизирую этой точке зрения, я не могу не заметить, что варианты использования, для которых вам нужны оба контекста (совместное использование объектов между фильтрами безопасности и сервлетами, автоматическое управление транзакциями, чтобы они закрывались после просмотра который вы перенаправляете на законченный рендеринг) довольно сложно добиться без помощи фреймворка. В основном это связано с тем, что API сервлетов явно никогда не предназначался для работы с внедрением зависимостей и активно работает против вас, если вы попытаетесь сделать это самостоятельно.
Periata Breatta,

@PeriataBreatta Понятно! Что ж, как вы думаете, если бы он был разработан по-другому, были бы лучшие альтернативы Spring MVC? Хотя люди все равно могли бы разработать полные альтернативы API сервлетов ...
Энди

@PeriataBreatta Интересно отметить, что в мире JS, где я использую Express для маршрутизации HTTP-запросов около года, я редко вижу упоминания о «внедрении зависимостей» и вообще ничего похожего на структуру Spring.
Энди

Ответы:


86

В вашем случае нет, незачем оставлять ContextLoaderListenerи applicationContext.xml. Если ваше приложение отлично работает только с контекстом сервлета, придерживаться этого будет проще.

Да, обычно поощряемый шаблон состоит в том, чтобы хранить не веб-материалы в контексте уровня веб-приложений, но это не более чем слабое соглашение.

Единственные веские причины использовать контекст уровня веб-приложений:

  • Если у вас несколько DispatcherServletкомпаний, которым нужно поделиться услугами
  • Если у вас есть устаревшие / не-Spring сервлеты, которым требуется доступ к службам Spring-wired
  • Если у вас есть сервлет фильтры, крючок в контексте WebApp уровня (например , Spring Security - х DelegatingFilterProxy, OpenEntityManagerInViewFilterи т.д.)

К вам ничего из этого не относится, поэтому дополнительная сложность неоправданна.

Просто будьте осторожны при добавлении фоновых задач в контекст сервлета, таких как запланированные задачи, соединения JMS и т. Д. Если вы забудете добавить <load-on-startup>в свой web.xml, эти задачи не будут запущены до первого обращения к сервлету.


2
Что касается слушателей, похоже, что им нужен Context, созданный слушателем Context Loader (IllegalStateException, WebApplicationContext не найден, запускается MultipartFilter, CharacterEncodingFilter, HiddenHttpMethodFilter, Spring Security DelegatingFilterProxy и OpenEntityManagerInViewFilter). Это хорошая идея сделать это наоборот (загрузить все с помощью ContextLoaderListener и оставить DispatcherServlet без конфигурации)?
Ralph

@ Ральф: Хороший улов, я добавил этот вариант использования в список. Что касается выхода DispatcherServletбез конфигурации - если бы вы это сделали, у вас не было бы веб-интерфейса. Все материалы MVC должны быть там.
skaffman

2
@skaffman Почему я должен использовать два контекста при использовании spring -security с DelegatingFilterProxy? В моем случае компоненты Spring-Security и контекст Spring по умолчанию используют некоторые компоненты. Таким образом, они также должны иметь общий контекст. Или компоненты безопасности Spring должны быть исключены из контекста Spring по умолчанию?
Matthias M

10

Вы можете настроить контекст приложения и наоборот. Например, чтобы заставить OpenEntityManagerInViewFilter работать. Настройте ContextLoaderListener, а затем настройте свой DispatcherServlet с помощью:

<servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value></param-value>
    </init-param>
</servlet>

Просто убедитесь, что значение параметра contextConfigLocation пустое.


1
Но в чем преимущество этой конфигурации? А что значит «наоборот»?
Ральф

Решение от «skaffman» настраивало только контекст веб-приложения (сервлет). Однако при таком подходе вы столкнетесь с проблемами, подробно описанными в самом решении: «Единственными вескими причинами для использования контекста уровня webapp являются:« ... »Если у вас есть фильтры сервлетов, которые подключаются к контексту уровня webbapp (например, DelegatingFilterProxy Spring Security, OpenEntityManagerInViewFilter и т. Д.) «Если вы хотите использовать только один XML-файл контекста приложения, я думаю, что мое решение (указание XML через ContextLoaderListener) будет предпочтительнее.
Gunnar Hillert

Можете ли вы использовать веб-контроллер MVC в контексте, созданном прослушивателем контекста?
Ральф

1
Да. Вы должны просто настроить свои контроллеры в файле context.xml, указанном прослушивателем контекста. Это работает так, что DispatcherServlet просто присоединяется к «контексту родительского приложения» (прослушиватель контекста). Если оставить значение contextConfigLocation пустым, файл context.xml, указанный прослушивателем контекста, будет использоваться исключительно.
Gunnar Hillert

1
Я думаю, вы пропустили <mvc: annotation-driven /> в своем контексте. Решение @GunnarHillert работает для меня.
milbr

10

Я хочу поделиться тем, что я сделал в своем приложении Spring-MVC:

  1. На we-mvc-config.xmlя добавил только классы аннотированные с @Controller:

    <context:component-scan base-package="com.shunra.vcat">
        <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>
  2. По applicationContext.xmlфайлам добавил все остальное:

    <context:component-scan base-package="com.shunra.vcat">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>

Да, это полезный шаблон. Другой полезный шаблон - просто поместить компоненты обработки базы данных в контекст приложения (они, вероятно, понадобятся для OpenSessionInViewFilter или аналогичного) вместе со всем, что конкретно необходимо фильтрам или слушателям (например, определениям, необходимым для использования безопасности Spring).
Periata Breatta,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.