2016-03-29 14 views
7

Background: Ho un'applicazione relativamente vecchia che utilizza Websphere MQ per la messaggistica. Funziona su WAS (Websphere Application Server) e utilizza MDB (Message Driven Beans). Sono riuscito a sostituire tutti gli MDB utilizzando Spring Integration - JMS. Il mio prossimo passo è provare a vedere se riesco a portarlo fuori da WAS in modo che possa essere eseguito su qualsiasi altro contenitore di servlet con un JRE non IBM (sto cercando: apache tomcat). Si noti che la protezione dei canali tramite SSL è un requisito. Preferisco usare JNDI.Spring Configuration per JMS (Websphere MQ - SSL, Tomcat, JNDI, Non IBM JRE)

Fine Obiettivo: disaccoppiare la mia applicazione dal server di applicazioni (WAS) e altri infrastrutture come la messaggistica (MQ). Ma portare fuori dal WAS su Tomcat è il primo passo. Poi viene il compito di aggiornare la mia infrastruttura di messaggistica con qualcosa di più scalabile. Questo mi consente di aggiornare i singoli componenti dell'infrastruttura su cui si basa la mia app, una cosa alla volta (app server, livello di messaggistica, archivio dati) senza interrompere troppo la mia applicazione.

Domanda: Ora, la mia sfida è definire le risorse JNDI su tomcat che possono accedere a Websphere MQ. Ho fatto qualche progresso su questo utilizzando i canali non SSL che ho definito nel file context.xml in questo modo:

<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"/> 

Il mio prossimo passo è quello di arrivare a questo lavoro con canali via SSL. Comprendo la parte che riguarda la configurazione dei keystore (file kdb e generazione e scambio di cert), la configurazione dei canali SSL su QM, ecc. Ho già tutto ciò che funziona. Come posso convincere Tomcat a utilizzare il mio keystore, la suite di crittografia, ecc.? Puntatori o un esempio di lavoro sarebbe fantastico!

Nota: sto utilizzando Spring Integration 4.2, Websphere MQ v8, Tomcat v9, attualmente.

Devo aggiungere che ho provato prima tutto senza JNDI. Quindi, ecco config non SSL la mia primavera JMS, senza la JNDI, che funziona:

<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> 

risposta

9

Credo di aver finalmente capito come tirare fuori questo ... Ecco una breve descrizione dei passaggi. Se hai bisogno di maggiori dettagli fammi sapere.

Pre-reqs: Websphere MQ Server installato (almeno v 8.0.0.2) Configurare il QM, canali SSL e non SSL, creare Qs e tutta quella roba buona è necessario. Inutile dire che sono necessari i barattoli di Websphere MQ. Essere consapevoli di eventuali restrizioni di licenza.

Passaggio 1: ottenere la connessione diretta senza SSL, senza JNDI. Avrete bisogno di usare questi fagioli per configurare in base JMS ascoltatori vostra primavera e JMS modelli ecc

<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> 

Fase 2: Prendi il collegamento diretto a lavorare con SSL, senza JNDI. Ho trovato l'impostazione un po 'complicata.

2a.Sin da quando ero utilizzando un non-IBM JRE, ho dovuto assicurarsi che le specifiche di cifratura & suite di cifratura necessari per essere configurate secondo le mappature specificate qui: http://www-01.ibm.com/support/docview.wss?uid=swg1IV66840

Questo significa, ovviamente, che abbiamo almeno avere il nostro Websphere MQ aggiornato a 8.0.0.2. Nel mio caso ho usato ECDHE_RSA_AES_256_GCM_SHA384 sulla canale SSL e configurato i fagioli JMS all'interno di un'applicazione da utilizzare TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, così:

<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. Crea certs, keystore (kdbs), exchange certs ecc. Ci sono molti modi per farlo. Ma tieni presente che dovrai memorizzare le password, l'etichetta chiave per il gestore code deve essere 'ibmwebspheremq qmgr' - tutto in minuscolo, senza spazi, (senza virgolette), l'etichetta chiave deve essere come 'ibmwebspheremq idutente '- tutto in lettere minuscole, senza spazi, (senza virgolette) dove userid è l'id utente che esegue tomcat. Se hai bisogno di maggiori dettagli su come l'ho fatto usando certs autografati, fammi sapere.

2c. Ora devi ottenere la JVM su cui viene eseguito tomcat, per leggere i tuoi keystore. Ci sono molti modi ma ecco come ho fatto: Creare un file setenv.bat nella cartella bin Tomcat, con i seguenti contenuti (debug SSL è opzionale)

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. Avviare Tomcat utilizzando il seguente comando:

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

Per fermare, basta premere Ctrl + C (su Windows). In qualunque modo tu lo faccia, assicurati che setenv.bat sia usato durante l'avvio. Oppure usa JAVA_OPTS per impostare le proprietà del keystore.

2e. Verifica che l'utilizzo del canale SSL funzioni.

Fase 3: Ottenere una connessione JNDI lavorare con i non-SSL, JNDI Ci sono molti era quello di istituire JNDI su Tomcat. Ecco come ho fatto: all'interno dell'applicazione Web creare un file META-INF/context.xml con il seguente contenuto:

<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"/> 

Ora nella configurazione primavera, al posto delle configurazioni diretti, tutto quello che dovete fare è :

Si noti che, per brevità, non ho utilizzato riferimenti di risorse. Nel caso in cui lo fai, ci sono alcuni passaggi aggiuntivi che sono semplici.

Passaggio 4: Ora il passaggio finale consiste nell'utilizzare un canale SSL e JNDI. Supponendo di aver fatto il punto 2, questo è facile. Modificare il META-INF/context.xml con il seguente contenuto:

<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"/> 

Nota la linea con SCPHS = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384". Se è necessario impostare altri tali parametri, vedere la colonna "Short Form" in questo link: https://www.ibm.com/support/knowledgecenter/SSFKSJ_8.0.0/com.ibm.mq.ref.dev.doc/q111800_.htm%23jm10910_?lang=en

Speriamo che tutto questo funziona per voi. In bocca al lupo!

Una volta che questa configurazione funziona, l'invio di messaggi è piuttosto semplice. Ma questo è come si può ascoltare per un messaggio su una coda utilizzando Primavera JMS Riferimento: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/jms.html

Fase 1: DefaultMessageListenerContainer Usa primavera e configurare i fagioli in un file XML in questo modo (primavera-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> 

Fase 2: Aggiungi questo al vostro 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> 

Fase 3: Scrivere una classe Message Listener in questo modo:

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"); 
     } 
    } 
} 

In alternativa, al posto del punto 3, se si utilizza l'integrazione di primavera, si può fare qualcosa in questo modo:

<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> 
+0

in dettaglio spiegazione +1. –

+0

Dove si sta configurando Step1? nome del file, è in spring-beans.xml o in qualche altro file e come lo leggerà. – Chinmoy

+0

È il file XML in cui si configurano i bean di primavera (potrebbe essere suddiviso in più file). Assicurati che venga preso in considerazione nel tuo web.xml (se non può essere prelevato per impostazione predefinita in base alle convenzioni di denominazione) – code4kix

Problemi correlati