我想在系统收到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?
感谢您的任何提示!
答案 0 :(得分: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();
}
不漂亮,但我几乎可以肯定这会奏效。