首页 文章

传递JMS消息时刷新Spring上下文

提问于
浏览
2

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

以下是示例代码段:

<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 shutdown:

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所以也许是某种bug?

谢谢你的任何提示!

1 回答

  • 2

    你能解释一下为什么需要这种复杂的架构吗?收到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();
    }
    

    不漂亮,但我几乎肯定这会奏效 .

相关问题