Конфигурация Spring для JMS (Websphere MQ-SSL, Tomcat, JNDI, не IBM JRE)
Справочная информация: У меня есть относительно старое приложение, которое использует Websphere MQ для обмена сообщениями. Он работает на WAS (Websphere Application Server) и использует MDBs (компоненты, управляемые сообщениями). Мне удалось успешно заменить все MDBs с помощью Весенняя интеграция-JMS. Мой следующий шаг-попытаться увидеть, могу ли я перенести его из WAS, чтобы он мог работать на любом другом контейнере сервлетов с не-IBM JRE (я пытаюсь: apache tomcat). Обратите внимание, что защита каналов с помощью SSL требование. Я предпочитаю использовать JNDI.
Цель: Чтобы отделить мое приложение от сервера приложений (WAS) и другой инфраструктуры, такой как messaging (MQ). Но взять это из WAS на tomcat - это первый шаг. Далее следует задача обновления инфраструктуры обмена сообщениями с помощью чего-то более масштабируемого. Это позволяет мне обновлять отдельные компоненты инфраструктуры, на которые опирается мое приложение, по одному (сервер приложений, уровень обмена сообщениями, хранилище данных) без я слишком часто прерываю свою работу.
вопрос: Теперь моя задача-определить ресурсы JNDI на tomcat, которые могут получить доступ к Websphere MQ. Я добился некоторого прогресса в этом, используя каналы без SSL, которые я определил в контексте.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="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 и сертификатами), настройку каналов SSL на QM etc. У меня все это уже работает. Как заставить tomcat использовать хранилище ключей, набор шифров и т. д.? Указатели или рабочий пример, было бы здорово!
Примечание: В настоящее время я использую Spring Integration 4.2, Websphere MQ v8, Tomcat v9.
Я должен добавить, что я сначала попробовал все без JNDI. Итак, вот мой spring JMS non-ssl config без JNDI, который работает:
<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>
1 ответов
кажется, я наконец-то понял, как это провернуть... вот краткое описание шагов. Если вам нужны подробности, дайте мне знать.
предварительные требования: Установлен сервер Websphere MQ (не менее v 8.0.0.2) Настройте каналы QM, SSL и non-SSL, создайте Qs и все, что вам нужно. Излишне говорить, что вам нужны банки Websphere MQ. Помните о любых лицензионных ограничениях.
Шаг 1: получить прямое соединение Работа без SSL, без JNDI. Вам нужно будет использовать эти компоненты для настройки прослушивателей JMS на основе spring и шаблонов 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. Мне показалось, что это немного сложно.
2а. Поскольку я использовал не IBM JRE, я должен был убедиться, что спецификации и комплекты шифров должны быть настроены в соответствии с указанными сопоставлениями здесь: http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840
это, очевидно, означает, что мы, по крайней мере, должны обновить Websphere MQ до 8.0.0.2. В моем случае я использовал ECDHE_RSA_AES_256_GCM_SHA384 на канале SSL и настроил бобы jms в приложении для использования 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), сертификатов exchange и т. д. Есть много способов сделать это. Но помните, что вам нужно будет спрятать пароли, метка ключа для администратора очередей должна быть " ibmwebspheremqна "qmgr"’ - все в нижнем регистре, без пробелов (без кавычек), метка ключа должна быть как " ibmwebspheremquserid’ - все в нижнем регистре, без пробелов (без кавычек), где userid-это идентификатор пользователя, который запускает tomcat. Если вам нужна более подробная информация о том, как я это сделал, используя самозаверяющие сертификаты, дайте мне знать.
2c. Теперь вы должны получить JVM, который работает tomcat, чтобы прочитать ваши хранилища ключей. Есть много способов, но вот как я это сделал: Создать setenv.bat-файл в папке Tomcat bin со следующим содержимым (отладка 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"
2Д. Запустите tomcat, используя следующую команду:
catalina.bat run > ..\logs\tomcat.log 2>&1
чтобы остановить, просто нажмите ctrl+c (в windows). Как бы то ни было, убедитесь, что setenv.bat используется во время запуска. Или использовать JAVA_OPTS для установки ключей свойства.
2e. Убедитесь,что работает канал SSL.
Шаг 3: получите соединение JNDI, работающее с не-SSL, JNDI Есть много, чтобы настроить JNDI на tomcat. Вот как я это сделал: в веб-приложении создайте файл 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"/>
теперь в вашей весенней конфигурации вместо прямых конфигураций все, что вам нужно сделать есть:
<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, это легко. Измените мета-INF/контекст.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-файле, например (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: добавьте это в ваш веб -.в 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: напишите класс прослушивателя сообщений следующим образом:
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");
}
}
}
альтернативно, вместо шага 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>