Spring による JMS のメッセージ送受信サンプル

Spring JMS Templateの簡単なサンプル

先日はJMSによるRMIを見ましたが、ここではもう少し低レベルなJMSのメッセージ送受信について見ていきます。使用ライブラリは前回と同一です。

使用ライブラリ

Spring関連

  • spring.jar(2.5.5)
  • spring-test.jar(2.5.5)

ActiveMQ関連

  • activemq-all-5.2.0.jar
  • xbean-spring-3.4.jar

JUnit

メッセージ送信側

JMSメッセージの送受信には JmsTemplate が用意されています。ここではメッセージの送信に template.send を使用しています。送信するメッセージはテキストメッセージとしています。

package etc9;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

public class JmsMessageProducer {

    @Autowired
    private JmsTemplate template;

    public void simpleSend(final String msg) {
        template.send( new MessageCreator() {
            public Message createMessage(Session session) throws JMSException {
                TextMessage message = session.createTextMessage("Text Message from Producer:" + msg);
                return message;
            }
        });
    }
}

メッセージ受信側

JmsMessageConsumerなどを用意して JmsTemplate を使うことで MDPs(message-driven POJOs) ではない普通のJMSメッセージのやり取りもできます。が、ここでは MessageListener を実装したリスナーを用意し、メッセージドリブンで処理が行われるようにします。といっても実装は onMessage() に処理を書くだけです。

package etc9;

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

public class JmsMessageListener implements MessageListener {

    public void onMessage(Message message) {
        try {   
            if (message instanceof TextMessage) {
                TextMessage tm = (TextMessage)message;
                String msg = tm.getText();
                System.out.println(msg);
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

テストケース

テストケースを以下のようにします。JmsMessageProducer からメッセージ"hoge"を送信するだけです。受信側はメッセージの到着で自動的に処理が行われます。

package etc9;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import etc9.JmsMessageProducer;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class JmsMessageListenerTest {

    @Autowired
    public JmsMessageProducer jmsMessageProducer;
    
    @Test
    public void testMessage() throws Exception {
        jmsMessageProducer.simpleSend("hoge");
    }
}

テストケース用Spring設定

JmsMessageListenerTest-context.xml をテストケースと同じディレクトリに用意します。全文は末尾に記載します。

ActiveMQの設定

ActiveMQの設定は前回と同様に組み込みモードとして定義しています。

    <!-- create an embedded ActiveMQ Broker -->
    <amq:broker id="broker" useJmx="false" persistent="false">
      <amq:transportConnectors>
        <amq:transportConnector uri="tcp://localhost:0" />
      </amq:transportConnectors>
    </amq:broker>
    
    <!--  ActiveMQ Destination  -->
    <amq:queue id="destination" physicalName="jms.test" />
    
    <!-- embedded モードでの MessageBroker を使用  -->
    <amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />
JMS Producer 側の設定
    <!-- JMS Producer Configuration -->
    <bean id="jmsProducerConnectionFactory" 
          class="org.springframework.jms.connection.SingleConnectionFactory"
          depends-on="broker"
          p:targetConnectionFactory-ref="jmsFactory" />

    <bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
          p:connectionFactory-ref="jmsProducerConnectionFactory"
          p:defaultDestination-ref="destination" />

    <bean id="jmsMessageProducer" class="etc9.JmsMessageProducer" />
JMS Consumer 側の設定
    <!-- JMS Consumer Configuration -->
    <bean id="jmsMessageListener" class="etc9.JmsMessageListener" />
    <bean id="jmsConsumerConnectionFactory" 
          class="org.springframework.jms.connection.SingleConnectionFactory"
          depends-on="broker"
          p:targetConnectionFactory-ref="jmsFactory" />
        
    <!-- JMS Namespace によるリスナーコンテナの設定 -->
    <jms:listener-container container-type="default" 
                            connection-factory="jmsConsumerConnectionFactory"
                            acknowledge="auto">
        <jms:listener destination="jms.test" ref="jmsMessageListener" />
    </jms:listener-container>

実行結果

コンソールに以下の出力が得られれば成功です。

Text Message from Producer:hoge

JmsMessageListenerTest-context.xml 全文

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:amq="http://activemq.apache.org/schema/core"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/jms 
                           http://www.springframework.org/schema/jms/spring-jms.xsd
                           http://activemq.apache.org/schema/core 
                           http://activemq.apache.org/schema/core/activemq-core.xsd">

    <amq:broker id="broker" useJmx="false" persistent="false">
        <amq:transportConnectors>
            <amq:transportConnector uri="tcp://localhost:0" />
        </amq:transportConnectors>
    </amq:broker>
    <amq:queue id="destination" physicalName="jms.test" />
    <amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />


    <bean id="jmsProducerConnectionFactory" 
          class="org.springframework.jms.connection.SingleConnectionFactory"
          depends-on="broker"
          p:targetConnectionFactory-ref="jmsFactory" />
    <bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
          p:connectionFactory-ref="jmsProducerConnectionFactory"
          p:defaultDestination-ref="destination" />
    <bean id="jmsMessageProducer" class="etc9.JmsMessageProducer" />


    <bean id="jmsMessageListener" class="etc9.JmsMessageListener" />
    <bean id="jmsConsumerConnectionFactory" 
          class="org.springframework.jms.connection.SingleConnectionFactory"
          depends-on="broker"
          p:targetConnectionFactory-ref="jmsFactory" />
    <jms:listener-container container-type="default" 
                            connection-factory="jmsConsumerConnectionFactory"
                            acknowledge="auto">
        <jms:listener destination="jms.test" ref="jmsMessageListener" />
    </jms:listener-container>

</beans>

JMS ネームスペースなど使用しない場合

JMS ネームスペースなどを使用しない JmsMessageListenerTest-context.xmlの例です。動作的には同じです・・

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:amq="http://activemq.apache.org/schema/core"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://activemq.apache.org/schema/core 
                           http://activemq.apache.org/schema/core/activemq-core.xsd">

    <amq:broker id="broker" useJmx="false" persistent="false">
      <amq:transportConnectors>
        <amq:transportConnector uri="tcp://localhost:0" />
      </amq:transportConnectors>
    </amq:broker>
    <amq:queue id="destination" physicalName="jms.test" />
    <amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost" />


    <bean id="jmsMessageProducer" class="etc9.JmsMessageProducer" />
    <bean id="jmsProducerConnectionFactory" 
        class="org.springframework.jms.connection.SingleConnectionFactory">
      <property name="targetConnectionFactory"><ref local="jmsFactory" /></property>
    </bean>
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
      <property name="connectionFactory" ref="jmsProducerConnectionFactory" />
      <property name="defaultDestination" ref="destination" />
    </bean>
    
    
    <bean id="jmsMessageListener" class="etc9.JmsMessageListener" />
    <bean id="jmsConsumerConnectionFactory" 
          class="org.springframework.jms.connection.SingleConnectionFactory">
      <property name="targetConnectionFactory" ref="jmsFactory" />
    </bean>
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
      <property name="connectionFactory" ref="jmsConsumerConnectionFactory"/>
      <property name="destinationName" value="jms.test" />
      <property name="messageListener" ref="jmsMessageListener" />
    </bean>

</beans>