2014-01-13 73 views
0

我正在使用以下DefaultMessageListenerContainer創建一個持久訂閱,即使在停機時間也能收到消息,這非常有效。是否有可能使用spring jms停止並重新啓動持久訂閱?

@Bean 
ConnectionFactory connectionFactory() { 
    SingleConnectionFactory connectionFactory = new SingleConnectionFactory(new ActiveMQConnectionFactory(
      AMQ_BROKER_URL)); 
    connectionFactory.setClientId(CLIENT_ID); 
    return connectionFactory; 
} 

@Bean 
DefaultMessageListenerContainer container(final MessageListener messageListener, 
     final ConnectionFactory connectionFactory) { 
    return new DefaultMessageListenerContainer() { 
     { 
      setMessageListener(messageListener); 
      setConnectionFactory(connectionFactory); 
      setDestinationName(JMS_TARGET); 
      setPubSubDomain(true); 
      setSessionTransacted(true); 
      setSubscriptionDurable(true); 
      setDurableSubscriptionName(SUBSCRIPTION_ID);       
      setConcurrentConsumers(1); 
     } 
    }; 
} 

問題是:當我不再需要它時,刪除訂閱的最佳方法是什麼?是否有可能暫時刪除訂閱(並錯過一些消息),但以後再啓用它?

到目前爲止工作的唯一方法是關閉DMLC並在之後退出調用。

dmlc.shutdown(); 
Connection connection = connectionFactory.createConnection(); 
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
session.unsubscribe(SUBSCRIPTION_ID); 

這是一個合理的解決方案嗎?如何重新啓動訂閱?

我已經看到this answer但我真的不知道該怎麼做?或者,以完全不同的方式訂閱和取消訂閱會更好嗎?

回答

0

在我建議我的答案之前,請允許我提醒一句:暫時刪除持久訂閱聽起來有點像您並不需要持久訂閱。持久訂閱用於Consumers,它需要接收在脫機時發送的消息。如果您有時只需要消息(例如,當您的消費者連接時),則非持久話題是首選項。

請注意,這僅適用於Topics(1:n溝通,pub/sub)。 Queues的工作方式與1:1通信(先進技術,如現在預留的負載均衡)略有不同。

持久的主題會在消息代理上產生明顯的資源開銷,並且刪除和重新創建訂閱可能會一次又一次地導致代價高昂的初始化。

現在,如果你真的想(臨時)從你的持久主題訂閱(也適用於「正常」的主題),你就必須延長DefaultMessageListenerContainer

public class MyContainer extends DefaultMessageListenerContainer { 
    public Session retrieveSession() { 
     return getSession(); // this is protected, so we wrap it (could also make getSession public) 
    } 
} 

當你實例MyContainer(而不是DefaultMessageListenerContainer)在container方法,確保存儲參考:

protected MyContainer listenerContainer; 
... 
listenerContainer = new MyContainer(...); 
return listenerContainer; 

然後,您可以只調用listenerContainer.retrieveSession().unsubscribe(...)退訂。

另請注意,您只能在該會話的所有消費者關閉該主題並且沒有正在傳輸的消息(直接引用documentation:「客戶刪除持久訂閱時出錯有一個活躍的(不是封閉的)消費者用於訂閱,或者當消費的消息是未完成的交易的一部分或者在會話中未被確認。「

+0

感謝您的詳細解答。我同意您對un - /一次又一次地訂閱,但我很好奇它是如何工作的,它不會每天都進行操作,因此問題依然存在:手動取消/訂閱的最佳方式是什麼?您的建議「只」取消訂閱,但由於getSession需要JmsR,所以我仍然遇到這個問題esourceHolder實例。此外,雖然我無法測試您的解決方案,但我想我也會因爲消費者仍然活躍而出現錯誤。這就是爲什麼我需要在「我的提議」之前調用dmlc.shutdown()。 – Ingo

+0

由於您正在創建一個全新的會話(它將獲得自己的客戶端ID),因此您仍然必須修改您的方法,因此您不會從發出訂閱的同一個會話中取消訂閱:您的舊訂閱將保持活動狀態 – SirRichie

+0

你確定嗎? clientId在connectionFactory中設置,因此我認爲會話將​​獲得相同的clientId。不過,我怎樣才能獲得最初的會話呢?如前所述,我需要一個JmsResourceHolder實例,對吧? – Ingo

相關問題