Spring MVC: общий контекст в ухе
У меня есть пакет уха, который содержит одну банку с общими объектами и два военных веб-приложения, которые я хотел бы использовать в общей банке. Я настроил конфигурацию для использования широкого контекста приложения через контексты ContextLoaderListener и webapp отдельно для DispatcherServlet.
Настройка моего демонстрационного приложения примерно следующая
-
common.jar
содержит applicationContext.xml и beanRefContext.xml, которые должны быть широким контекстом приложения (уха). Файлы выглядят следующим образом. shared namespace - это место, где расположен общий bean.
ApplicationContext
<beans>
<!-- namespace etc declarations omitted -->
<context:annotation-config />
<context:component-scan base-package="study.spring.multicontext.shared" />
</beans>
beanRefContext.xml
<beans>
<!-- namespace etc declarations omitted -->
<bean id="sharedContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg>
<list>
<value>classpath*:applicationContext.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
-
webapp1
и webapp2
являются Spring приложениями MVC, упакованными как отдельные войны с файлом web.xml, как показано ниже
<web-app>
<context-param>
<param-name>parentContextKey</param-name>
<param-value>sharedContext</param-value>
</context-param>
<context-param>
<param-name>locatorFactorySelector</param-name>
<param-value>classpath:beanRefContext.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dos</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dos-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dos</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
и xx-servlet.xml, например, для контекста webapp. веб-пространство имен - это место, где расположены контроллеры.
<beans>
<!-- namespace etc declarations omitted -->
<context:component-scan base-package="study.spring.multicontext.web"/>
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"/>
</bean>
</beans>
-
Общий bean @Autowired обычным образом в классах контроллера
@Autowired
MySharedBean mySharedBean
-
пакет уха содержит как войны, так и банку, а структура похожа на
ear
|
|--common.jar
| |--META-INF
| |--applicationContext.xml
| |--beanRefContext.xml
|
|--webapp1.war
| |--WEB-INF
| |--xx-servlet.xml
| |--web.xml
|
|--webapp2.war
| |--WEB-INF
| |--xx-servlet.xml
| |--web.xml
Проблема в том, что все еще будут два экземпляра bean. Один для каждого контроллера /webapp, поскольку в каждой из войн есть только один контроллер. Я попытался перевернуть конфигурацию, но независимо от того, что я делаю, я либо получаю нулевые экземпляры, либо два экземпляра.
Я проверил ссылки с Eclipse MAT из дампа памяти, и на самом деле есть 4 экземпляра, но я думаю, что эти два предназначены для внутреннего использования Spring. Во всяком случае, оттуда ясно видно, что каждый контроллер имеет свой собственный экземпляр.
Я читал множество сообщений в блогах, дискуссионных форумах и т.д., где они говорят, что это должно быть так просто. Некоторые предлагают JNDI, но, как я понял, это возможно без него.
И невозможно объединить войны и объединить банку внутри. Поскольку это может работать для этого демонстрационного приложения, реальный случай жизни, с которым я работаю, не позволяет этого.
Любая помощь по этому вопросу высоко ценится. Спасибо заранее.
Пример SpringSource с 2007 г. для Spring 2.X, который делает то же самое, но с другой конфигурацией. Немного устарел и ищет решение на основе Spring 3.X, как описано в описании награды.
Ответы
Ответ 1
Я решил его решить.
Проблема была в загрузке классов, как я подозревал в комментариях к ответу @Akshay.
Maven включил spring libs внутри каждого военного пакета, поэтому они были загружены несколько раз. Чтобы исправить это, нужно генерировать тощие войны.
Я предполагаю, что Akshay отмечает, что его ответ на удаление contextConfigLocation
из контекстных параметров в web.xml также был ключевым.
Ответ 2
Я не верю, что что-то изменилось с Spring 2.x на 3.x в отношении иерархии контекстов приложения.
Из того, что я могу сказать, проблема с вашей конфигурацией заключается в том, что вы загружаете applicationContext.xml
- тот, который загружен в sharedContext
, также загружается каждым webapp, из-за того, что его упомянутых в context-param
contextConfigLocation
.
Поскольку один и тот же файл загружается дважды, один раз в родительском контексте и один раз в корневом контексте веб-приложения, есть сделанные копии и дочерний контекст, т.е. webapp, использует те, которые он создал, а не те, которые присутствуют в родительском.
Измените свою конфигурацию, чтобы дважды не перезагружать один и тот же beans xml, и он должен работать нормально. Вы можете использовать parentContextKey
и contextConfigLocation
как просто не загружать те же файлы.
Обновление:
В дополнение к вышесказанному, вам также необходимо проверить, видима ли общая банка для войн (видимая, как в разрешении на использование одного и того же экземпляра). Я попытался запустить образец из блога, и это не сработало для меня, когда я развернул его как приложение Java EE6, и это потому, что правила для видимости ящика для уха в войнах изменились с Java EE5 на EE6. Когда я запускаю образец в режиме совместимости Glass Fish, все работает так, как ожидалось.
Итак, проверьте свои EAR/WARs, чтобы узнать, какие функции сервлета вы используете, и убедитесь, что ваш сервер использует приложение соответствующим образом.
Если вам нужно перейти на Java EE 6, убедитесь, что вы следуете последним правилам видимости http://docs.oracle.com/cd/E19226-01/820-7688/gjjdt/index.html. Проверьте файлы MANIFEST
войн, чтобы убедиться, что они имеют все ушные банки, явно упомянутые в конфигурации Class-Path
.
Надеюсь, что это поможет.
Ответ 3
У нас была аналогичная проблема. Проверьте этот простой пример maven (EAR с 2 WEB-модулями и общим через родительский spring контекстный сервисный модуль), который мы создали для эксперимента:
EAR с общим spring контекстом между войнами
Ответ 4
Хотя этот вопрос старый, если кому-то интересно, почему документированный подход не работает в Spring Framework 5. 0+. Поддержка совместного использования контекста в ухе в настоящее время нарушена в Spring Framework 5. 0+ на момент публикации этого ответа. Существует открытая проблема в Spring Framework Issue-20805