簡體   English   中英

使用 Spring Boot 和 AMQP 訂閱 Azure 服務總線主題

[英]Subscribing to an Azure Service Bus Topic with Spring Boot and AMQP

我設置了一個名為“state-changed”的 Azure 服務總線主題,它有一個名為“reverb”的訂閱。 我正在嘗試使用@JmsListener設置一個方法來訂閱該主題,但出現錯誤:

2017-03-22 18:34:41.049  WARN 23356 --- [enerContainer-6] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'state-changed' - trying to recover. Cause: The messaging entity 'sb://[MySERVICEBUS].servicebus.windows.net/state-changed' could not be found. TrackingId:d2b442f79e0f44bdb449861ea57155ce_G44, SystemTracker:gateway6, Timestamp:3/22/2017 6:34:37 PM

javax.jms.JMSException: The messaging entity 'sb://[MySERVICEBUS].servicebus.windows.net/state-changed' could not be found. TrackingId:d2b442f79e0f44bdb449861ea57155ce_G44, SystemTracker:gateway6, Timestamp:3/22/2017 6:34:37 PM
    at org.apache.qpid.amqp_1_0.jms.impl.TopicSubscriberImpl.createClientReceiver(TopicSubscriberImpl.java:111) ~[qpid-amqp-1-0-client-jms-0.32.jar:0.32]
    at org.apache.qpid.amqp_1_0.jms.impl.MessageConsumerImpl.<init>(MessageConsumerImpl.java:129) ~[qpid-amqp-1-0-client-jms-0.32.jar:0.32]
    at org.apache.qpid.amqp_1_0.jms.impl.TopicSubscriberImpl.<init>(TopicSubscriberImpl.java:46) ~[qpid-amqp-1-0-client-jms-0.32.jar:0.32]
    at org.apache.qpid.amqp_1_0.jms.impl.SessionImpl.createDurableSubscriber(SessionImpl.java:544) ~[qpid-amqp-1-0-client-jms-0.32.jar:0.32]
    at org.apache.qpid.amqp_1_0.jms.impl.SessionImpl.createDurableSubscriber(SessionImpl.java:59) ~[qpid-amqp-1-0-client-jms-0.32.jar:0.32]
    at org.springframework.jms.listener.AbstractMessageListenerContainer.createConsumer(AbstractMessageListenerContainer.java:870) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.createListenerConsumer(AbstractPollingMessageListenerContainer.java:215) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.initResourcesIfNecessary(DefaultMessageListenerContainer.java:1189) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1165) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055) ~[spring-jms-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_77]

我一直在使用這篇博文來嘗試讓一切正常運行: http : //ramblingstechnical.blogspot.co.uk/p/using-azure-service-bus-with-spring-jms.html

我可以使用JmsTemplate向主題添加消息,並使用 Azure 文檔中概述的普通舊 Java JMS 庫從中讀取消息: https : //docs.microsoft.com/en-us/azure/service-bus-messaging/service -bus-java-how-to-use-jms-api-amqp所以我知道我的主題確實有效並且可以訪問,似乎只是當我用 Spring 配置它時我做錯了什么。

我的配置看起來像:

@Configuration
public class JmsConfiguration
{

    @Bean
    public JmsListenerContainerFactory topicJmsListenerContainerFactory() throws NamingException
    {
        DefaultJmsListenerContainerFactory returnValue = new DefaultJmsListenerContainerFactory();

        Context context = context();
        ConnectionFactory cf = connectionFactory(context);

        returnValue.setConnectionFactory(cf);
        returnValue.setSubscriptionDurable(Boolean.TRUE);
        return returnValue;
    }

    private Context context() throws NamingException
    {
        Hashtable<String, String> env = new Hashtable<String, String>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
        env.put(Context.PROVIDER_URL, "src/main/resources/servicebus.properties");
        Context context = new InitialContext(env);
        return context;
    }



    /**
     * @param context
     * @return
     * @throws NamingException
     */
    private ConnectionFactory connectionFactory(Context context) throws NamingException
    {
        ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
        return cf;
    }

}

servicebus.properties(用戶名和密碼等已編輯):

# servicebus.properties - sample JNDI configuration

# Register a ConnectionFactory in JNDI using the form:
# connectionfactory.[jndi_name] = [ConnectionURL]
connectionfactory.SBCF=amqps://[USER]:[PASSWORD]@[MYSERVICEBUS]

# Register some queues in JNDI using the form
# queue.[jndi_name] = [physical_name]
# topic.[jndi_name] = [physical_name]
queue.workflow = workflow
topic.state-changed = stage-changed

最后是我的聽眾課:

@Component
public class TestListener
{
    Logger logger = LoggerFactory.getLogger(LoggingWorkflowEventHandler.class);

    @JmsListener(destination = "state-changed", containerFactory = "topicJmsListenerContainerFactory", subscription = "reverb")
    public void onMessage(String message)
    {
        logger.info("Received message from topic: {}", message);
    }
}

如果有人設法使這項工作正常進行,我將不勝感激。

您的錯誤消息表明未找到您的目的地名稱(未找到消息實體)。 請注意,您需要以特定方式告訴 Azure 您的訂閱名稱,如下所示:

<TopicName>/Subscriptions/<SubscriptionName>

在你的情況下:

state-changed/Subscriptions/reverb

希望有幫助

干杯塞布

如果你使用 Spring Boot,你可以使用准備好的 Azure ServiceBus JMS Spring Boot Starter,它可以開箱即用。

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-servicebus-jms-spring-boot-starter</artifactId>
    <version>2.3.5</version>
</dependency>

查看教程頁面https://docs.microsoft.com/en-us/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-service-bus

創建或更改 Trustrore:

由於我們要建立到服務總線的安全 amqps 連接,我們需要將所有必需的 SSL 證書存儲在信任庫中。 似乎現有的證書都不包含所需的證書,我 - 為了透明度 - 創建了一個這樣的新證書:

通過在瀏覽器中訪問https://<URL-Of-Your-Servicebus>獲取所需的證書,例如https://XXXXX.servicebus.cloudapi.de 然后單擊 URL 中的“鎖定”(或您的瀏覽器顯示的任何安全連接)並從那里打開證書。

保存當前證書:

[證書提供 ]

當詢問要導出的格式時,選擇“DER binary”並將其另存為“.cer”文件,例如“1.cer”

您很可能會看到您的證書基於證書鏈,這意味着它依賴於其他證書。 對於每個點擊“顯示證書”:

[證書提供 ]

並以與之前相同的方式保存那個。 重復直到到達根證書。 在本例中,您將得到三個 *.cer 文件。 為了進一步參考,我將它們稱為 1.cer、2.cer 和 3.cer

您現在應該為這些證書創建一個新的 Truststore 文件

/opt/webMethods9/jvm/jvm/bin/keytool -import -file
/opt/webMethods9/IntegrationServer/instances/default/packages/DEV_fse/resources/1.cer -keystore azureTruststore.jks -alias "D-TRUST Root Class 3 CA 2 2009"

/opt/webMethods9/jvm/jvm/bin/keytool -import -file 
/opt/webMethods9/IntegrationServer/instances/default/packages/DEV_fse/resources/2.cer -keystore azureTruststore.jks -alias "D-TRUST SSL Class 3 CA 1 2009"

/opt/webMethods9/jvm/jvm/bin/keytool -import -file 
/opt/webMethods9/IntegrationServer/instances/default/packages/DEV_fse/resources/3.cer -keystore azureTruststore.jks -alias "servicebus.cloudapi.de"

第一次將要求您為這個新創建的信任庫設置密碼。 現在將信任庫移動到/opt/webMethods9/IntegrationServer/config/certs/trusted (供以后參考)。 您可以將它作為信任庫添加到 IS(通過使用管理界面“安全 > 密鑰庫”和“創建信任庫別名”),但沒有技術需要這樣做,因為在我們的情況下,IS 沒有使用信任庫- 它僅由 QPID 使用。

為 JNDI 創建一個屬性文件 您需要創建一個servicebus.properties文件來充當偽 JNDI 服務器的數據源。 從技術上講,您可以將該文件放在任何您想要的位置,但我建議將其放在“XXXXXXConnection”包的“resources”文件夾中。 這應該是該文件的內容:

# servicebus.properties - sample JNDI configuration
# Register a ConnectionFactory in JNDI using the form:
# connectionfactory.[jndi_name] = [ConnectionURL]
connectionfactory.SBCF = amqps://XXXXXX.servicebus.cloudapi.de?jms.username=xxxxx&jms.password=xxxxxxx&amqp.idleTimeout=120000&jms.receiveLocalOnly=true&transport.trustStoreLocation=/opt/webMethods9/IntegrationServer/config/certs/trusted/azureTruststore.jks
# Register some queues in JNDI using the form 
# queue.[jndi_name] = [physical_name] 
# topic.[jndi_name] = [physical_name]
queue.QUEUE = myqueue
​

一些解釋:

  1. SBCF將是連接工廠的 JNDI-Lookup 名稱。 稍后在您的 JMS-Connection 中需要此名稱
  2. xxxxxx.servicebus.cloudapi.de是您的服務總線的 URL
  3. jms.username將由友好的 Azure 管理員提供
  4. jms.password將由友好的 Azure 管理員提供。 但請注意,您需要對將從管理員那里獲得的內容進行 URL 編碼,然后才能在此 URL 中使用它。 例如,這可以通過在設計器中手動調用 IS 服務pub.string:URLEncode來完成。
  5. amqp.idleTimeout需要設置為 120000(或更高),否則你無法連接到 SB
  6. jms.receiveLocalOnly需要設置為true否則你無法連接到 SB
  7. transport.trustStoreLocation需要將包含創建安全 (AMQPS) 連接所需的所有 SSL 證書的信任庫指向 SB
  8. queue.QUEUE : QUEUE 是 JNDI-Lookup 名稱,您稍后將在 JMS-Client 中使用它來發送消息或在 JMS-Trigger 中用於接收它們。 你應該設置一個更有意義的東西。 此值(示例中的“myqueue”)是 SB 上隊列的名稱,必須由 Azure 管理員提供。

[JNDI 上下文工廠類 ]

僅有的兩個重要值是:

  1. “初始上下文工廠”: org.apache.qpid.jms.jndi.JmsInitialContextFactory
  2. “Provider URL”:必須指向您創建的 servicebus.properties,例如file:/opt/webMethods9/IntegrationServer/instances/default/packages/XXXXXXConnection/resources/servicebus.properties

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM