简体   繁体   English

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

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

Background: I have a relatively old application that uses Websphere MQ for messaging. 背景:我有一个相对较旧的应用程序,它使用Websphere MQ进行消息传递。 It runs on WAS (Websphere Application Server) and uses MDBs (Message Driven Beans). 它在WAS(Websphere Application Server)上运行并使用MDB(消息驱动Bean)。 I was successfully able to replace all MDBs using Spring Integration - JMS . 我成功地使用Spring Integration - JMS替换了所有MDB。 My next step is try to see if I can port it out of WAS so that it can run on any other servlet container with a non-IBM JRE (I am trying: apache tomcat). 我的下一步是尝试查看是否可以将其移出WAS,以便它可以在任何其他具有非IBM JRE的servlet容器上运行(我正在尝试:apache tomcat)。 Note that securing channels using SSL is a requirement. 请注意,使用SSL保护通道是必需的。 I prefer using JNDI. 我更喜欢使用JNDI。

End Goal: To decouple my application from the application server (WAS) and other infrastructure like messaging (MQ). 最终目标:将我的应用程序与应用程序服务器(WAS)和其他基础结构(如消息传递(MQ))分离。 But taking this out of WAS onto tomcat is the first step. 但是将这个从WAS中取出来到tomcat是第一步。 Next comes the task of updating my messaging infrastructure with something more scalable. 接下来是使用更具可伸缩性的东西更新我的消息传递基础结构 This allows me to update individual components of the infrastructure that my app relies on, one thing at a time (app server, messaging layer, datastore) without disrupting my application too much, as I go. 这使我能够更新我的应用所依赖的基础架构的各个组件,一次一件事(应用服务器,消息传递层,数据存储),而不会过多地中断我的应用程序。

Question: Now, my challenge is to define JNDI resources on tomcat that can access Websphere MQ. 问:现在,我的挑战是在tomcat上定义可以访问Websphere MQ的JNDI资源。 I have made some progress on this using non-SSL channels that I defined in the context.xml file like so: 我使用我在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"/>

My next step is to get this to work with SSL channels. 我的下一步是使用SSL通道。 I understand the part that involves setting up the keystores (kdb file and cert generation and exchanging), configuring the SSL channels on the QM etc. I have all that working already. 我理解涉及设置密钥库(kdb文件和证书生成和交换),在QM等上配置SSL通道的部分。我已经完成了所有工作。 How do I get tomcat to use my keystore, cipher suite etc? 如何让tomcat使用我的密钥库,密码套件等? Pointers or a working example would be great! 指针或工作示例会很棒!

Note: I am using Spring Integration 4.2, Websphere MQ v8, Tomcat v9, currently. 注意:我目前正在使用Spring Integration 4.2,Websphere MQ v8,Tomcat v9。

I must add that I did try everything without the JNDI first. 我必须补充一点,我确实在没有JNDI的情况下尝试了一切。 So here's my spring jms non-ssl config without the JNDI, that works: 所以这里是没有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> 

I think I finally figured out how to pull this off... here's a brief description of the steps. 我想我终于想出了如何解决这个问题......这里是对步骤的简要描述。 If you need more details let me know. 如果您需要更多详细信息,请通知我。

Pre-reqs : Websphere MQ Server installed (at least v 8.0.0.2) Configure the QM, SSL and non-SSL channels, create Qs and all that good stuff you need. 预先要求 :安装了Websphere MQ Server(至少v 8.0.0.2)配置QM,SSL和非SSL通道,创建Q以及您需要的所有好东西。 Needless to say, you need the Websphere MQ jars. 不用说,您需要Websphere MQ jar。 Be mindful of any licensing restrictions. 请注意任何许可限制。

Step 1 : Get the direct connection working with no SSL, no JNDI. 步骤1 :使用没有SSL,没有JNDI的直接连接。 You will need to use these beans to configure your spring based JMS listeners and JMS Templates etc. 您将需要使用这些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>

Step 2 : Get the direct connection working with SSL, no JNDI. 第2步 :使用SSL进行直接连接,没有JNDI。 I found setting this up a little tricky. 我觉得设置这个有点棘手。

2a . 2a Since I was using a non-IBM JRE, I had to make sure the cipher specs & cipher suites needed to be configured according to the mappings specified here: http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840 由于我使用的是非IBM JRE,因此我必须确保需要根据此处指定的映射配置密码规范和密码套件: http//www-01.ibm.com/support/docview.wss? UID = swg1IV66840

This obviously means that we at least have to have our Websphere MQ upgraded to 8.0.0.2. 这显然意味着我们至少必须将Websphere MQ升级到8.0.0.2。 In my case I used ECDHE_RSA_AES_256_GCM_SHA384 on the SSL channel and configured the jms beans within application to use TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, like so: 在我的例子中,我在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 . 2b Create certs, keystores (kdbs), exchange certs etc. There are many ways to do this. 创建证书,密钥库(kdbs),交换证书等。有很多方法可以做到这一点。 But be mindful that you will need to stash passwords, the key label for the queue manager must be 'ibmwebspheremq qmgr ' – all in lower case, no spaces, (without quotes), the key label must be like 'ibmwebspheremq userid ' – all in lower case, no spaces, (without quotes) where userid is the userid that runs tomcat. 但请注意,您需要存储密码,队列管理器的密钥标签必须是'ibmwebspheremq qmgr ' - 全部为小写,无空格(无引号),密钥标签必须为'ibmwebspheremq userid ' - 全部小写,没有空格,(没有引号)其中userid是运行tomcat的用户标识。 If you need more details on exactly how I did it using self signed certs, let me know. 如果您需要有关我如何使用自签名证书的详细信息,请告诉我们。

2c . 2c Now you have to get the JVM that tomcat runs, to read your keystores. 现在你必须得到tomcat运行的JVM来读取你的密钥库。 There are many ways but here's how I did it: Create a setenv.bat file in the tomcat bin folder, with the following contents (debugging SSL is optional) 有很多方法,但这里我是这样做的:在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 . 2d Start tomcat using the following command: 使用以下命令启动tomcat:

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

To stop, just press ctrl+c (on windows). 要停止,只需按ctrl + c(在Windows上)。 Whichever way you do it, make sure that setenv.bat is used during start up. 无论您采用哪种方式,都要确保在启动期间使用setenv.bat。 Or use JAVA_OPTS to set the keystore properties. 或使用JAVA_OPTS设置密钥库属性。

2e . 2e Verify that the using the SSL channel works. 验证使用SSL通道是否有效。

Step 3 : Get a JNDI connection working with non-SSL, JNDI There are many was to set up JNDI on tomcat. 步骤3 :使用非SSL,JNDI获取JNDI连接有很多是在tomcat上设置JNDI。 Here's how I did it: Within the web application create a file META-INF/Context.xml with the following contents: 以下是我的工作方式:在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"/>

Now in your spring config, instead of the direct configurations, all you have to do is: 现在在你的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" />

Note that for brevity, I just didn't use resource references. 请注意,为简洁起见,我只是没有使用资源引用。 In case you do, there a few additional steps which are straight forward. 如果你这样做,还有一些额外的步骤是直截了当的。

Step 4 : Now the final step is to use an SSL channel and JNDI. 第4步 :现在最后一步是使用SSL通道和JNDI。 Assuming you have done step 2, this is easy. 假设您已完成第2步,这很容易。 Modify the META-INF/Context.xml with the following contents: 使用以下内容修改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"/>

Note the line with SCPHS="TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384". 注意SCPHS =“TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384”的行。 If you need to set other such parameters, see the "Short Form" column in this link: https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q111800_.htm%23jm10910_?lang=en 如果您需要设置其他此类参数,请参阅此链接中的“简短表格”栏: https//www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/ q111800_.htm%23jm10910_?LANG = EN

Hopefully all this works for you. 希望这一切都适合你。 Good luck! 祝好运!

Once this configuration works, sending messages is pretty straight forward. 一旦此配置有效,发送消息就非常简单。 But this is how you can listen for a message on a queue using Spring JMS Reference: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html 但是你可以使用Spring JMS参考来监听队列中的消息: https//docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html

Step 1 : Use Spring's DefaultMessageListenerContainer and configure your beans in an xml file like so (spring-beans.xml): 步骤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>

Step 2 : Add this to your web.xml 第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>

Step 3 : Write a Message Listener class like so: 第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");
        }
    }
}

Alternatively, instead of step 3, if you are using spring integration, you can do something like so: 或者,如果您使用的是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