我想在系统收到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 回答
你能解释一下为什么需要这种复杂的架构吗?收到JMS消息时重新加载应用程序上下文?听起来很疯狂(或者可能是巧妙的?)
尽管如此,我并不是100%确定,但您提供的信息非常明确:您正在尝试在使用JMS消息时关闭应用程序上下文 . 但由于消费者是Spring管理的,因此上下文无法被销毁,因为它等待所有bean完成 - 包括Spring Integration消息使用者所需的
ConfigurationReloader
. 并且ConfigurationReloader
无法完成,因为它等待上下文被销毁(refresh()
正在阻止) .简单地说 - 你已经引入了循环依赖和死锁 .
解决方案很简单 - 延迟上下文刷新,以便在JMS消息消耗之后发生 . 最简单的方法是:
不漂亮,但我几乎肯定这会奏效 .