2011-11-14 10 views
2

システムがJMSメッセージを受信したときにアプリケーションコンテキストをリフレッシュしたいと思います。これを行うために、Spring Integration jms:message-driven-channel-adapterを設定して、ApplicationContextAwareを実装するサービスアクティベータにメッセージを転送します。このアクティベータ(ConfigurationReloaderクラス)は、ConfigurableApplicationContext#refresh()メソッドを呼び出します。JMSメッセージが配信されたときのSpringコンテキストのリフレッシュ

以下

サンプルコードスニペットです:

<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 ew構成パラメータはメッセージとともに配信されます。 これは最新のSpringCoreとSpring Integrationに基づいて、前面にDispatcherServletを持つ標準のSpring MVCアプリケーションです。また、コントローラを介してConfigurationLoaderを呼び出すとうまく動作するため、JMS関連の問題であると確信しています。私がデバッグきたよう

、それ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で管理されているため、Spring Integrationメッセージコンシューマが必要とするコンシューマを含め、すべてのBeanが終了するのを待つため、コンテキストを破棄することはできません。 ConfigurationReloaderは、コンテキストが破棄されるのを待つため終了できません(refresh()がブロックしています)。

単純に言えば、サイクリック依存性とデッドロックが導入されました。

解決策は簡単です。コンテキストリフレッシュを遅延させて、JMSメッセージの消費後に発生させるようにします。最も簡単な方法は次のとおりです。

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

これはうまくいかないとは思うが、私はこれがうまくいくと確信している。

+0

うん、それは、ありがとう! 私はそれが独創的かどうかわかりませんが、確かにちょっと狂っています;)私が達成しようとしているのは、ある種の動的統合層です。コンポーネント(つまり、統合レイヤー全体)の設計はJMSを介して行われます。 あなたはデッドロックについて正しくありました。もう1つの解決法(もっと単純な方法)は、DirectChannelではなくQueueChannelを使用することです。メッセージがキューに入れられると、DMLCリスナー・スレッドは処理を終了します。その後、メッセージはキューから取得され、コンテキストはデッドロックなしで同じスレッドからリフレッシュされます。 –

関連する問題