如何将Spring应用上下文事件桥接到另一个上下文?

19

我有一个使用Spring框架的Web应用程序,其中包含两个上下文:一个是由ContextLoaderListener创建的(applicationContext),另一个是由DispatcherServlet创建的(webContext)。

applicationContext中有一个bean (org.springframework.security.authentication.DefaultAuthenticationEventPublisher),该bean触发Spring上下文事件。

但是事件的接收者在webContext中被定义。然而,这个接收者没有收到事件。(如果将接收器为测试目的放置在applicationContext中,则会收到事件,但我无法这样做,因为我需要webContext来完成其功能。)

因此我的问题是,如何将事件从applicationContext桥接到webContext


你找到解决问题的方法了吗? - Andrés Oviedo
我猜Spring的设计不允许你这样做。否则,如果你正在调试哪个类处理事件,那么这不是非常令人困惑吗?现在,你不仅需要查看一个容器内部,还需要查看所有容器。 - gerrytan
5个回答

10

我曾经遇到过同样的问题,通过将创建事件的bean移动到web-context中来解决了我的问题。不过你也可以通过手动连接你的事件监听器来解决问题,类似于这样(这段代码未编译,因此未经测试):

@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) {
    }

}

4

我认为实际的答案可能是您需要不同地配置应用程序(这样您只有一个上下文)。 我认为在您的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文件中使用包含(实际上,在上面的示例中,您可以在分派servlet中指定多个springconfig)。 但是,当您包含其他上下文文件时,您不共享bean实例,只共享定义。
将Spring应用程序模块化一直是与EJB等相比Spring的唯一真正缺点。这导致Spring使用OSGi。 而要回答您背后的问题,即如何共享Spring上下文,官方答案是使用OSGi(Spring DM)在上下文之间共享Spring bean实例。

3
尝试将事件发布者移动到Web上下文文件中,这样它就可以在整个应用程序上下文中可见。当配置父应用程序上下文中的方法安全性时,会出现类似的问题。父应用程序上下文(由ContextLoaderListener加载)不知道子(Web)上下文的存在。
如果您不需要两者之间的父子关系,则还可以为整个应用程序使用单个应用程序上下文。通常它只会妨碍事情的进行,如果所有bean都在同一空间中定义,那么就更容易了。

这不是解决方案,因为问题是如何处理这两个上下文。我不能将安全设置移动到Web上下文中,因为我在应用程序中明确使用它(这是一个具有ACL的应用程序)。 - Ralph
你真的需要两个独立的应用程序上下文吗?听起来可能更简单只有一个。 - Shaun the Sheep
这听起来好多了。我会检查为什么我使用了两个上下文,并看看是否可以合并它们。 - Ralph
通常情况下,两个上下文是默认设置。作为替代方案,您可以只使用DispatcherServlet上下文,并使用导入语句添加其他上下文文件。 - Shaun the Sheep
1
需要两个上下文(在我的情况下),因为一些过滤器(如Spring Security的DelegatingFilterProxy)需要父上下文。请参见https://dev59.com/Hmox5IYBdhLWcg3wtmnh - Ralph

3

0
我们可以使用import标签来导入/桥接两个不同的上下文,以便事件/bean的可见性可用并共享。
<import resource="applicationContext_name.xml"/>

在这个导入中,上下文xml被配置为从ContextLoaderListener中创建,在DispatcherServlet的上下文xml中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接