簡體   English   中英

JMS的Spring配置(Websphere MQ - SSL,Tomcat,JNDI,非IBM JRE)

[英]Spring Configuration for JMS (Websphere MQ - SSL, Tomcat, JNDI, Non IBM JRE)

背景:我有一個相對較舊的應用程序,它使用Websphere MQ進行消息傳遞。 它在WAS(Websphere Application Server)上運行並使用MDB(消息驅動Bean)。 我成功地使用Spring Integration - JMS替換了所有MDB。 我的下一步是嘗試查看是否可以將其移出WAS,以便它可以在任何其他具有非IBM JRE的servlet容器上運行(我正在嘗試:apache tomcat)。 請注意,使用SSL保護通道是必需的。 我更喜歡使用JNDI。

最終目標:將我的應用程序與應用程序服務器(WAS)和其他基礎結構(如消息傳遞(MQ))分離。 但是將這個從WAS中取出來到tomcat是第一步。 接下來是使用更具可伸縮性的東西更新我的消息傳遞基礎結構 這使我能夠更新我的應用所依賴的基礎架構的各個組件,一次一件事(應用服務器,消息傳遞層,數據存儲),而不會過多地中斷我的應用程序。

問:現在,我的挑戰是在tomcat上定義可以訪問Websphere MQ的JNDI資源。 我使用我在context.xml文件中定義的非SSL通道在這方面取得了一些進展,如下所示:

<Resource
   name="jms/qcf_sandbox"
   auth="Container"
   type="com.ibm.mq.jms.MQQueueConnectionFactory"
   factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
   description="JMS Queue Connection Factory for sending messages"
   HOST="localhost"
   PORT="1414"
   CHAN="CHANNEL_SANDBOX"
   TRAN="1"
   QMGR="QM_SANDBOX"/>
<Resource
   name="jms/SandboxQ"
   auth="Container"
   type="com.ibm.mq.jms.MQQueue"
   factory="com.ibm.mq.jms.MQQueueFactory"
   description="JMS Queue"
   QU="SANDBOX_Q"/>

我的下一步是使用SSL通道。 我理解涉及設置密鑰庫(kdb文件和證書生成和交換),在QM等上配置SSL通道的部分。我已經完成了所有工作。 如何讓tomcat使用我的密鑰庫,密碼套件等? 指針或工作示例會很棒!

注意:我目前正在使用Spring Integration 4.2,Websphere MQ v8,Tomcat v9。

我必須補充一點,我確實在沒有JNDI的情況下嘗試了一切。 所以這里是沒有JNDI的我的spring jms non-ssl配置,它的工作原理如下:

<bean id="mq-jms-cf-sandbox"
   class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
    <ref bean="mqQueueConnectionFactory" />
    </property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
   <property name="hostName" value="localhost" />
   <property name="port" value="1414" />
   <property name="queueManager" value="QM_SANDBOX" />
   <property name="transportType" value="1" />
   <property name="channel" value="CHANNEL_SANDBOX" />
 </bean>
 <bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
   <constructor-arg value="SANDBOX_Q" />
    <property name="baseQueueManagerName">
    <value>QM_SANDBOX</value>
    </property>
    <property name="baseQueueName">
    <value>SANDBOX_Q</value>
    </property>
</bean> 

我想我終於想出了如何解決這個問題......這里是對步驟的簡要描述。 如果您需要更多詳細信息,請通知我。

預先要求 :安裝了Websphere MQ Server(至少v 8.0.0.2)配置QM,SSL和非SSL通道,創建Q以及您需要的所有好東西。 不用說,您需要Websphere MQ jar。 請注意任何許可限制。

步驟1 :使用沒有SSL,沒有JNDI的直接連接。 您將需要使用這些bean來配置基於Spring的JMS偵聽器和JMS模板等。

<bean id="mq-jms-cf-sandbox"
   class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
    <ref bean="mqQueueConnectionFactory" />
    </property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
   <property name="hostName" value="localhost" />
   <property name="port" value="1414" />
   <property name="queueManager" value="QM_SANDBOX" />
   <property name="transportType" value="1" />
   <property name="channel" value="NON_SSL_CHANNEL" />
 </bean>
 <bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
   <constructor-arg value="SANDBOX_Q" />
    <property name="baseQueueManagerName">
    <value>QM_SANDBOX</value>
    </property>
    <property name="baseQueueName">
    <value>SANDBOX_Q</value>
    </property>
</bean>

第2步 :使用SSL進行直接連接,沒有JNDI。 我覺得設置這個有點棘手。

2a 由於我使用的是非IBM JRE,因此我必須確保需要根據此處指定的映射配置密碼規范和密碼套件: http//www-01.ibm.com/support/docview.wss? UID = swg1IV66840

這顯然意味着我們至少必須將Websphere MQ升級到8.0.0.2。 在我的例子中,我在SSL通道上使用了ECDHE_RSA_AES_256_GCM_SHA384,並在應用程序中配置了jms bean以使用TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,如下所示:

<bean id="mq-jms-cf-sandbox"
    class="org.springframework.jms.connection.SingleConnectionFactory">
    <property name="targetConnectionFactory">
        <ref bean="mqQueueConnectionFactory" />
    </property>
</bean>
<bean id="mqQueueConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
  <property name="hostName" value="localhost" />
  <property name="port" value="1414" />
  <property name="queueManager" value="QM_SANDBOX" />
  <property name="transportType" value="1" />
  <property name="channel" value="SSL_CHANNEL" />
  <property name="SSLCipherSuite" value="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/>
</bean>
<bean id="jms-destination-sandbox" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="SANDBOX_Q" />
    <property name="baseQueueManagerName">
       <value>QM_SANDBOX</value>
    </property>
    <property name="baseQueueName">
       <value>SANDBOX_Q</value>
    </property>
</bean>

2b 創建證書,密鑰庫(kdbs),交換證書等。有很多方法可以做到這一點。 但請注意,您需要存儲密碼,隊列管理器的密鑰標簽必須是'ibmwebspheremq qmgr ' - 全部為小寫,無空格(無引號),密鑰標簽必須為'ibmwebspheremq userid ' - 全部小寫,沒有空格,(沒有引號)其中userid是運行tomcat的用戶標識。 如果您需要有關我如何使用自簽名證書的詳細信息,請告訴我們。

2c 現在你必須得到tomcat運行的JVM來讀取你的密鑰庫。 有很多方法,但這里我是這樣做的:在tomcat bin文件夾中創建一個setenv.bat文件,其中包含以下內容(調試SSL是可選的)

set JAVA_OPTS="-Djavax.net.ssl.trustStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.trustStorePassword=topsecret" "-Djavax.net.ssl.keyStore=C:\path-to-keystore\key.jks" "-Djavax.net.ssl.keyStorePassword=topsecret" "-Djavax.net.debug=ssl" "-Dcom.ibm.mq.cfg.useIBMCipherMappings=false"

2d 使用以下命令啟動tomcat:

catalina.bat run > ..\logs\tomcat.log 2>&1 

要停止,只需按ctrl + c(在Windows上)。 無論您采用哪種方式,都要確保在啟動期間使用setenv.bat。 或使用JAVA_OPTS設置密鑰庫屬性。

2e 驗證使用SSL通道是否有效。

步驟3 :使用非SSL,JNDI獲取JNDI連接有很多是在tomcat上設置JNDI。 以下是我的工作方式:在Web應用程序中創建一個文件META-INF / Context.xml,其中包含以下內容:

<Resource
   name="jms/qcf_sandbox"
   auth="Container"
   type="com.ibm.mq.jms.MQQueueConnectionFactory"
   factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
   description="JMS Queue Connection Factory for sending messages"
   HOST="localhost"
   PORT="1414"
   CHAN="NON_SSL_CHANNEL"
   TRAN="1"
   QMGR="QM_SANDBOX"/>
<Resource
   name="jms/SandboxQ"
   auth="Container"
   type="com.ibm.mq.jms.MQQueue"
   factory="com.ibm.mq.jms.MQQueueFactory"
   description="JMS Queue"
   QU="SANDBOX_Q"/>

現在在你的spring配置中,而不是直接配置,你所要做的就是:

<jee:jndi-lookup id="mq-jms-cf-sandbox" jndi-name="java:/comp/env/jms/qcf_sandbox" resource-ref="false" />
<jee:jndi-lookup id="jms-destination-sandbox" jndi-name="java:/comp/env/jms/SandboxQ" resource-ref="false" />

請注意,為簡潔起見,我只是沒有使用資源引用。 如果你這樣做,還有一些額外的步驟是直截了當的。

第4步 :現在最后一步是使用SSL通道和JNDI。 假設您已完成第2步,這很容易。 使用以下內容修改META-INF / Context.xml:

<Resource
   name="jms/qcf_sandbox"
   auth="Container"
   type="com.ibm.mq.jms.MQQueueConnectionFactory"
   factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
   description="JMS Queue Connection Factory for sending messages"
   HOST="localhost"
   PORT="1414"
   CHAN="SSL_CHANNEL"
   TRAN="1"
   QMGR="QM_SANDBOX"
   SCPHS="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"/>
<Resource
   name="jms/SandboxQ"
   auth="Container"
   type="com.ibm.mq.jms.MQQueue"
   factory="com.ibm.mq.jms.MQQueueFactory"
   description="JMS Queue"
   QU="SANDBOX_Q"/>

注意SCPHS =“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”的行。 如果您需要設置其他此類參數,請參閱此鏈接中的“簡短表格”欄: https//www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/ q111800_.htm%23jm10910_?LANG = EN

希望這一切都適合你。 祝好運!

一旦此配置有效,發送消息就非常簡單。 但是你可以使用Spring JMS參考來監聽隊列中的消息: https//docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html

步驟1 :使用Spring的DefaultMessageListenerContainer並在像這樣的xml文件中配置bean(spring-beans.xml):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"      
    "http://www.springframework.org/dtd/spring-beans.dtd">

   <!-- this is the Message Driven POJO (MDP) -->
   <bean id="messageListener" class="jmsexample.ExampleListener" />

   <!-- and this is the message listener container -->
   <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
       <property name="connectionFactory" ref="mq-jms-cf-sandbox"/>
       <property name="destination" ref="jms-destination-sandbox"/>
       <property name="messageListener" ref="messageListener" />
   </bean>

</beans>

第2步 :將其添加到您的web.xml

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/context/spring-beans.xml</param-value>
 </context-param>

<listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

第3步 :編寫一個Message Listener類,如下所示:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class ExampleListener implements MessageListener {

    public void onMessage(Message message) {
        if (message instanceof TextMessage) {
            try {
                System.out.println(((TextMessage) message).getText());
            }
            catch (JMSException ex) {
                throw new RuntimeException(ex);
            }
        }
        else {
            throw new IllegalArgumentException("Message must be of type TextMessage");
        }
    }
}

或者,如果您使用的是Spring集成,則可以執行以下操作,而不是步驟3:

<int:channel id="jms-inbound"/>
    <int-jms:message-driven-channel-adapter
        id="jms-inbound-adapter" container="jmsContainer" channel="jms-inbound" 
        extract-payload="true" acknowledge="transacted" 
        message-converter="messagingMessageConverter" />

<beans:bean id="messagingMessageConverter" class="org.springframework.jms.support.converter.MessagingMessageConverter">
    </beans:bean>

暫無
暫無

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

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