ContextLoaderListener чи ні?


122

Стандартний весняний веб-додаток (створений Roo або «Шаблон весняного проекту MVC») створить web.xml з ContextLoaderListenerта DispatcherServlet. Чому вони не просто використовують DispatcherServletі роблять це для завантаження повної конфігурації?

Я розумію, що ContextLoaderListener слід використовувати для завантаження речей, що не стосуються Інтернету, і DispatcherServlet використовується для завантаження відповідних веб-матеріалів (Controllers, ...). І це виходить у двох контекстах: батьківський та дитячий контекст.

Фон:

Я робив це стандартним чином кілька років.

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

Це часто спричиняло проблеми з двома контекстами та залежностями між ними. У минулому я завжди міг знайти рішення, і у мене є сильне відчуття, що це робить структуру / архітектуру програмного забезпечення завжди кращою. Але зараз я стикаюся з проблемою подій обох контекстів .

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

Чи є якісь причини не видаляти ContextLoaderListener?


"Це часто спричиняло проблеми з двома контекстами та залежностями між ними". Це чудовий приклад того, як я думаю, що схеми введення залежності залежать від того, щоб зробити наше життя важче, ніж робити самостійно.
Енді

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

@PeriataBreatta Я бачу! Ну, ви думаєте, якби це було розроблено інакше, то були б кращі альтернативи Spring MVC? Хоча люди могли б розробити повні альтернативи API сервлетів ...
Енді,

@PeriataBreatta Цікаво зазначити, що в світі JS, де я вже близько року використовую Express для маршрутизації HTTP-запитів, я рідко бачу згадки про "введення залежності" і взагалі нічого не нагадує рамки Spring.
Енді

Відповіді:


86

У вашому випадку, ні, немає ніяких причин зберігати ContextLoaderListenerі applicationContext.xml. Якщо ваш додаток добре працює лише з контекстом сервлета, це дотримується, це простіше.

Так, загальноприйнята модель полягає в тому, щоб зберігати не веб-матеріали в контексті рівня webapp, але це не більше ніж слабка умова.

Єдиними переконливими причинами використання контексту на рівні webapp є:

  • Якщо у вас декілька DispatcherServlet, вам потрібно ділитися службами
  • Якщо у вас є застарілі / непружинні сервлети, яким потрібен доступ до провідних сервісів Spring
  • Якщо у вас є сервлет фільтри, гачок в контексті WebApp рівня (наприклад , Spring Security - х DelegatingFilterProxy, OpenEntityManagerInViewFilterі т.д.)

Жодне з них не стосується вас, тому додаткова складність є невиправданою.

Будьте обережні, додаючи фонові завдання до контексту сервлета, як-от заплановані завдання, з'єднання JMS тощо. Якщо ви забудете додати <load-on-startup>до своїх web.xml, то ці завдання не будуть запускатися до першого доступу сервлета.


2
Що стосується слухачів, то, здається, їм потрібен створений контекстом слухач навантажувача контексту (IllegalStateException, не знайдено WebApplicationContext, спровокований MultipartFilter, CharacterEncodingFilter, HiddenHttpMethodFilter, Spring Security DelegatingFilterProxy і OpenIntererFilterFilterFilterProxyer). Це гарна ідея зробити це навпаки (Завантажте кожну річ ContextLoaderListener і залиште DispatcherServlet без конфігурації)?
Ральф

@Ralph: Хороший улов, я додав цей список використання до списку. Що стосується залишення DispatcherServletбез конфігурації - якби ви це зробили, у вас не було б веб-інтерфейсу. Усі речі MVC повинні зайти туди.
скафман

2
@skaffman Чому я повинен використовувати два контексти, коли використовую захист весни за допомогою DelegatingFilterProxy? У моєму випадку боби весняної безпеки та контекст весни за замовчуванням поділяють деякі боби. Тому вони також повинні поділяти той самий контекст. Або слід зберігати весняні боби безпеки поза весняним контекстом за замовчуванням?
Маттіас М

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>

Просто переконайтеся, що значення параметраComfigLocation порожнє.


1
Але в чому перевага цієї конфігурації? А що ви маєте на увазі під "навпаки"?
Ральф

Рішення "skaffman" налаштовувало лише контекст веб-додатків (сервлет). Однак, при такому підході ви стикаєтеся з питаннями, деталізованими в самому рішенні: "Єдиними переконливими причинами для використання контексту на рівні webapp є:" ... "Якщо у вас є фільтри сервлетів, які залучаються в контекст рівня webbapp (наприклад, Spring Security's DelegatingFilterProxy, OpenEntityManagerInViewFilter тощо) "Якщо ви хочете використовувати лише один XML-файл контексту програми, я думаю, що моє рішення (із зазначенням XML через ContextLoaderListener) було б кращим.
Gunnar Hillert

чи можете ви використовувати веб-контролер MVC у контексті, створеному слухачем контексту?
Ральф

1
Так. Ви просто встановите свої контролери у файл context.xml, визначений слухачем контексту. Як він працює, DispatcherServlet просто приєднається до "батьківського контексту програми" (контекстного слухача). Коли ви залишите значення "contextConfigLocation", порожнє файл контексту.xml, визначений слухачем контексту, буде використовуватися виключно.
Гуннар Гіллерт

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

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 або подібного), а також все, що конкретно потрібно фільтрам або слухачам (наприклад, визначення, необхідне для використання весняної безпеки).
Periata Breatta
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.