【问题标题】:Refreshing Spring context when JMS message deliveredJMS消息传递时刷新Spring上下文
【发布时间】:2011-12-28 18:05:12
【问题描述】:

我想在系统收到 JMS 消息时刷新我的应用程序上下文。为了做到这一点,我设置了 Spring Integration jms:message-driven-channel-adapter,它将消息转发到实现 ApplicationContextAware 的服务激活器。此激活器(ConfigurationReloader 类)调用 ConfigurableApplicationContext#refresh() 方法。

下面是示例代码sn-p:

 <jms:message-driven-channel-adapter id="jmsDriverConfigurationAdapter"
    destination="configurationApplyQueue" channel="jmsConfigurationInboundChannel" />

 <channel id="jmsConfigurationInboundChannel"/>

 <service-activator input-channel="jmsConfigurationInboundChannel" ref="configurationReloader" method="refresh"/>

还有我的激活器:

public final class ConfigurationReloader implements ApplicationContextAware {
        private ConfigurableApplicationContext applicationContext;

        public void refresh() {
           this.applicationContext.refresh();
        }

        @Override
        public void setApplicationContext(
                final ApplicationContext applicationContext) throws BeansException {
            if (applicationContext instanceof ConfigurableApplicationContext) {
                this.applicationContext =
                    (ConfigurableApplicationContext) applicationContext;
            }
        }
    }

在传递此类消息的情况下,上下文启动关闭操作但卡在 DefaultMessageListenerContainer bean 关闭:

2011-11-14 15:42:52,980 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Shutting down JMS listener container
2011-11-14 15:42:52,980 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Waiting for shutdown of message listener invokers
2011-11-14 15:42:55,104 [org.springframework.jms.listener.DefaultMessageLis tenerContainer#0-1] DEBUG org.springframework.jms.listener.DefaultMessageLis tenerContainer - Still waiting for shutdown of 1 message listener invokers

通过 JMS 调用此操作对我来说至关重要,因为新的配置参数与消息一起传递。 它是基于最新 SpringCore 和 Spring Integration 的标准 Spring MVC 应用程序,前端带有 DispatcherServlet。我也确信这是 JMS 相关的问题,因为通过控制器调用 ConfigurationLoader 工作正常。

正如我调试的那样,它在 DefaultMessageListenerContainer#538 行调用(lifecycleMonitor 上的 wait() 方法)之后卡住了:

/**
 * Destroy the registered JMS Sessions and associated MessageConsumers.
 */
protected void doShutdown() throws JMSException {
    logger.debug("Waiting for shutdown of message listener invokers");
    try {
        synchronized (this.lifecycleMonitor) {
            while (this.activeInvokerCount > 0) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Still waiting for shutdown of " + this.activeInvokerCount +
                            " message listener invokers");
                }
                this.lifecycleMonitor.wait();   // <--- line 538
            }
        }
    }
    catch (InterruptedException ex) {
        // Re-interrupt current thread, to allow other threads to react.
        Thread.currentThread().interrupt();
    }
}

...没有人可以在监视器上调用 notify/notifyAll,所以可能是某种错误?

感谢您的任何提示!

【问题讨论】:

    标签: spring spring-mvc spring-integration


    【解决方案1】:

    您能解释一下为什么需要如此复杂的架构吗?收到 JMS 消息时重新加载应用程序上下文?听起来很疯狂(或者可能很巧妙?)

    尽管如此,我不能 100% 确定,但您提供的信息非常清楚:您正在尝试在使用 JMS 消息时关闭应用程序上下文。但是由于消费者是 Spring 管理的,因此不能销毁上下文,因为它等待所有 bean 完成 - 包括 Spring Integration 消息消费者所需的 ConfigurationReloader。而ConfigurationReloader 无法完成,因为它等待上下文被销毁(refresh() 正在阻塞)。

    简单地说——你引入了循环依赖和死锁。

    解决方案很简单 - 延迟上下文刷新,使其在 JMS 消息消费之后发生。最简单的方法是:

    public void refresh() {
        Thread destroyThread = new Thread() {
            @Override
            public void run() {
                this.applicationContext.refresh();
            }
        };
        destroyThread.start();
    }
    

    不漂亮,但我几乎可以肯定这会奏效。

    【讨论】:

    • 是的,它有效,谢谢!我不知道它是否巧妙,但肯定有点疯狂;)我想要实现的是某种动态集成层。组件(以及整个集成层)的设计是通过 JMS 交付的。你对僵局的看法是对的。另一种解决方案(可能更简单)是使用 QueueChannel 而不是 DirectChannel。一旦消息被放入队列,DMLC 监听线程完成处理。然后,可以从队列中获取消息,并且可以从同一个线程刷新上下文而不会死锁。
    猜你喜欢
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 2015-06-07
    • 2013-06-22
    • 2020-03-29
    • 2011-03-27
    • 1970-01-01
    • 2015-01-09
    相关资源
    最近更新 更多