Как переместить Spring события контекста приложения в другой контекст
У меня есть веб-приложение Spring с двумя контекстами: один (applicationContext
), созданный ContextLoaderListener
, и второй (webContext
), построенный DispatcherServlet
.
Внутри applicationContext
находится bean (org.springframework.security.authentication.DefaultAuthenticationEventPublisher
), который запускает события контекста Spring.
Но приемник для события определяется в webContext
. И этот приемник не получил этого события. (Если поставить приемник для тестирования в applicationContext
, тогда он получит событие, но я не могу этого сделать, потому что для его функциональности нужен webContext
.)
Итак, мой вопрос заключается в том, как мостифицировать события от applicationContext
до webContext
?
Ответы
Ответ 1
У меня была та же проблема, решена моя, перемещая beans, создавая событие в веб-контекст. Однако вы можете решить свою проблему, вручную подключив прослушиватель событий, что-то вроде этого (этот код не компилируется, поэтому он не проверен):
@Component
public class BeanInWebContext implements ApplicationListener<SomeEvent> {
@Autowired
private ApplicationContext webContext;
@PostConstruct
public void registerAsListener() {
// get parent context
AbstractApplicationContext appContext = (AbstractApplicationContext) webContext.getParent();
// register self as a listener, this method is in AbstractApplicationContext
appContext.addApplicationListener(this);
}
@Override
public void onApplicationEvent(SomeEvent event) {
}
}
Ответ 2
Я думаю, что фактический ответ заключается в том, что вы можете настроить свое приложение по-другому (чтобы у вас был только один контекст)
Я думаю, что в вашем web.xml вам нужно сделать что-то вроде этого:
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/META-INF/applicationSpringConfig.xml
</param-value>
</init-param>
</servlet>
Но ответить на более глубокий вопрос. Кто-то еще указывает, что вы можете использовать, включив в ваш файл spring (действительно, в приведенном выше примере вы можете иметь более одного параметра springconfig, указанного в вашем сервлете диспетчера).
Но когда вы включаете другие файлы контекста, вы не обмениваетесь экземплярами beans, только определениями.
Модулизирующие приложения spring были единственным реальным недостатком spring по сравнению с EJB и т.д. Это привело к spring использованию OSGi.
И ответ на ваш основной вопрос о том, как обмениваться контентом spring, официально вы делите экземпляры spring bean между контекстами с помощью OSGi (spring dm)
Ответ 3
Попробуйте переместить издателя событий в файл веб-контекста, где он должен иметь видимость во всем контексте приложения. Аналогичная проблема возникает, когда настройка безопасности метода в контексте родительского приложения. Контекст родительского приложения (загруженный ContextLoaderListener
) не знает контекст child (web).
Вы также можете использовать один контекст приложения для всего приложения, если вам не нужны отношения между родителями и дочерними элементами между ними. Часто это просто мешает, и легче, если все beans были определены в одном и том же пространстве.
Ответ 4
Как указано в документации для структуры spring, простой механизм ApplicationEvent предназначен только для использования в одном и том же контексте приложения, я не знаю, что можно распространять события в дочерние контексты.
Если вам требуется более продвинутое решение, вы можете изучить более расширенное решение, такое как Java Message Service или spring Integration.
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events
Ответ 5
Мы можем использовать тег import для импорта/объединения двух разных контекстов, созданных таким образом, чтобы доступность и совместное использование видимых событий / beans.
<import resource="applicationContext_name.xml"/>
В этом примере импортируется контекст xml, который настроен для создания из ContextLoaderListener в контексте xml DispatcherServlet.