2

システムがJMSメッセージを受信したときに、アプリケーションコンテキストを更新したいと思います。これを行うために、ApplicationContextAwareを実装するサービスアクティベーターにメッセージを転送するSpring Integration jms:message-driven-channel-adapterを設定しました。このアクティベータ(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;
            }
        }
    }

このようなメッセージを配信する場合、コンテキストはシャットダウン操作を開始しますが、DefaultMessageListenerContainerBeanのシャットダウンでスタックします。

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に基づいて、前面にDispatcherServletを備えた標準のSpringMVCアプリケーションです。また、コントローラーを介したConfigurationLoaderの呼び出しは正常に機能するため、JMS関連の問題であると確信しています。

デバッグしたところ、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を呼び出す人がいないので、何らかのバグである可能性がありますか?

ヒントありがとうございます!

4

1 に答える 1

2

なぜそのような洗練されたアーキテクチャが必要なのか説明していただけますか? JMS メッセージの受信時にアプリケーション コンテキストをリロードしますか? クレイジーに聞こえます(または、独創的ですか?)

それにもかかわらず、私は 100% 確実ではありませんが、提供された情報は非常に明確です: JMS メッセージの消費中にアプリケーション コンテキストをシャットダウンしようとしています。ただし、コンシューマーは Spring で管理されているため、すべての Bean が完了するのを待機するため、コンテキストを破棄することはできませんConfigurationReloader(Spring Integration メッセージ コンシューマーが必要とするものを含む)。そして、コンテキストが破棄されるのを待っているため (ブロックしている) ConfigurationReloader、終了できません。refresh()

簡単に言えば、循環依存とデッドロックが発生しました。

解決策は簡単です。JMS メッセージの消費後にコンテキストの更新が行われるように、コンテキストの更新を遅らせます。最も簡単な方法は次のとおりです。

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

きれいではありませんが、これでうまくいくとほぼ確信しています。

于 2011-11-14T15:32:15.583 に答える