2011-11-14 28 views
2

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

下面是示例代码片段:

<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豆关机:

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调用这个操作对我来说非常重要,因为n新配置参数随消息一起传递。 这是标准的Spring MVC应用程序,基于最新的SpringCore和Spring Integration,DispatcherServlet在前端。另外,我确定它是JMS相关的问题,因为通过控制器调用ConfigurationLoader可以正常工作。

正如我调试,它stucks使用DefaultMessageListenerContainer#538行调用后(等待()上lifecycleMonitor法):

/** 
* 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(); 
    } 
} 

...有没有人打电话通知/ notifyAll的显示器上,所以也许它是某种错误?

感谢您的任何提示!

回答

2

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

不过,我不是100%肯定,但您所提供的信息是相当清楚的:你想关闭一个应用程序上下文,而消耗的JMS消息。但是由于消费者是Spring管理的,所以上下文不能被销毁,因为它等待所有bean完成 - 包括Spring集成消息使用者需要的ConfigurationReloader。而ConfigurationReloader无法完成,因为它等待上下文被破坏(refresh()阻止)。

简单地说 - 你介绍了一个循环依赖和死锁。

的解决方案是简单的 - 延迟上下文刷新,以便它JMS消息消费后会发生。最简单的方法是:

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

不漂亮,但我几乎可以肯定,这将工作。

+0

是的,它的工作原理,谢谢! 我不知道它是否巧妙,但肯定有点疯狂;)我试图实现的是某种动态集成层。通过JMS提供组件(以及整个集成层)的设计。 关于僵局你是对的。另一种解决方案(可能更简单)是使用QueueChannel而不是DirectChannel。一旦消息进入队列,DMLC监听器线程完成处理。然后,可能会从队列中获取消息,并且可能会从同一个线程刷新上下文而没有死锁。 –