Как переместить 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.