spring jms activemq


Spring integrates JMS (1) - Implements

    blog classification based on ActiveMQ: Spring Spring

JMS integrates integrateActiveMQ




1.1 Introduction

       to JMS The full name of JMS is Java Message Service, that is, Java Message Service. It is mainly used for message passing between producers and consumers, where producers are responsible for producing messages and consumers are responsible for receiving messages. If it is applied to the actual business requirements, we can use the producer to generate a message at a specific time and send it, and the corresponding consumer will complete the corresponding business logic after receiving the corresponding message. There are two types of message delivery, one is point-to-point, that is, a producer and a consumer correspond one-to-one; the other is publish/subscribe mode, that is, after a producer generates a message and sends it, it can be sent by multiple consumers to receive.
1.2 Spring integrates JMS

       After a brief introduction to JMS, let's talk about the specific process of Spring's integration of JMS. JMS is just a standard. When we really use it, we need to have its specific implementation. Here we use Apache's activeMQ as its implementation. The dependencies used are managed by Maven, and the specific dependencies are as follows:


Xml code Collection code

    <dependencies> 
            <dependency> 
                <groupId>junit</groupId> 
                <artifactId>junit</artifactId> 
                <version>4.10< 
                <scope>test</scope> 
            </dependency> 
            <dependency> 
                <groupId>org.springframework</groupId> 
                <artifactId>spring-context</artifactId> 
                <version>${spring-version}</version> 
            </dependency> 
            <dependency> 
                <groupId>org.springframework</groupId> 
                <artifactId>spring-jms</artifactId> 
                <version>${spring-version}</version> 
            </dependency> 
            <dependency> 
                <groupId>org.springframework</groupId> 
                <artifactId>spring-test</artifactId> 
                <version>${spring-version}</version> 
            </dependency> 
            <dependency> 
                <groupId>javax.annotation</groupId> 
                <artifactId>jsr250-api</artifactId> 
                <version>1.0</version> 
            </dependency> 
            <dependency> 
                <groupId>org.apache.activemq</groupId> 
                <artifactId>activemq-core</artifactId> 
                <version>5.7.0</version> 
            </dependency> 
    </dependencies> 


1.2.1  activeMQ准备

       Since we are using apache's activeMQ as the implementation of JMS, first we should download activeMQ (http://activemq.apache.org/download.html) from the apache official website, decompress it and run activemq.bat under its bin directory file to start activeMQ.
1.2.2 Configuring ConnectionFactory

       ConnectionFactory is used to generate links to the JMS server. Spring provides us with multiple ConnectionFactory, including SingleConnectionFactory and CachingConnectionFactory. SingleConnectionFactory will always return the same connection for requests to establish a JMS server connection, and will ignore the Connection's close method call. CachingConnectionFactory inherits SingleConnectionFactory, so it has all the functions of SingleConnectionFactory, and it also adds a caching function, which can cache Session, MessageProducer and MessageConsumer. Here we use SingleConnectionFactory as an example.
Xml code Collection code

    <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"/> 



       Does this define the ConnectionFactory that generates the JMS server connection? The answer is yes and no. The ConnectionFactory provided by Spring is only used by Spring to manage the ConnectionFactory. The ConnectionFactory that actually generates the link to the JMS server must be provided by the JMS service provider, and it needs to be injected into the ConnectionFactory provided by Spring. What we use here is JMS implemented by ActiveMQ, so what we can really generate Connection here should be the ConnectionFactory provided by ActiveMQ. So the complete code to define a ConnectionFactory should be as follows:
Xml code Collection code

    <!-- The ConnectionFactory that can really generate Connection, provided by the corresponding JMS service provider --> 
    <bean id="targetConnectionFactory" class="org.apache" .activemq.ActiveMQConnectionFactory"> 
        <property name="brokerURL" value="tcp://localhost:61616"/> 
    </bean> 
     
    <!-- Spring's ConnectionFactory to manage the real ConnectionFactory --> 
    <bean id= "connectionFactory" class="org.springframework. 
        <!-- The target ConnectionFactory corresponds to the real ConnectionFactory that can generate JMS Connection --> 
        <property name="targetConnectionFactory" ref="targetConnectionFactory"/> 
    </bean> 

 

       ActiveMQ provides us with a PooledConnectionFactory by injecting an ActiveMQConnectionFactory into it It can be used to pool Connection, Session and MessageProducer, which can greatly reduce our resource consumption. When using PooledConnectionFactory, we should define a ConnectionFactory as follows:


Xml code Collection code

    <!-- ConnectionFactory that can really generate Connection, provided by the corresponding JMS service provider --> 
    <bean id="targetConnectionFactory" class= "org.apache.activemq.ActiveMQConnectionFactory"> 
        <property name="brokerURL" value="tcp://localhost:61616"/> 
    </bean> 
     




     







       When we really use JmsTemplate to send messages, we need to know the destination of the message, that is, the destination. There is a Destination interface used to represent the destination in Jms. It does not have any method definition, but is only used as an identifier. When we do not specify the destination when using JmsTemplate for message sending, the default Destination will be used. The default Destination can be injected through the attribute defaultDestination or defaultDestinationName when defining the jmsTemplate bean object, and defaultDestinationName corresponds to a common string. Two types of Destinations are implemented in ActiveMQ, one is the point-to-point ActiveMQQueue, and the other is the ActiveMQTopic that supports the subscription/publishing mode. When defining these two types of Destinations, we can construct them through a name attribute, such as: Xml code Collection code














    <!--This is the queue destination, point-to-point--> 
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue"> 
        <constructor-arg> 
            <value>queue</value> 
        < /constructor-arg> 
    </bean> 
    <!--This is the topic destination, one-to-many--> 
    <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic"> 
        <constructor- arg value="topic"/> 
    </bean> 

       Suppose we define a ProducerService with a method sendMessage to send plain text messages to Destination, then our code looks like this:


Java code Collection code

    package com.tiantian .springintejms.service.impl; 
      
    import javax.annotation.Resource;   
    import javax.jms.Destination; 
    import javax.jms.JMSException; 
    import javax.jms.Message; 
    import javax.jms.Session; 
      
    import org.springframework.jms.core.JmsTemplate; 
    import org.springframework.jms.core.MessageCreator; 
    import org.springframework.stereotype.Component; 
      
    import com.tiantian.springintejms.service.ProducerService; 
      
    @Component 
    public class ProducerServiceImpl implements ProducerService { 
      
        private JmsTemplate jmsTemplate; 
         
        public void sendMessage(Destination destination, final String message) { 
            System.out.println("---------------生产者发送消息-----------------"); 
            System.out.println("---------------生产者发了一个消息:" + message); 
            jmsTemplate.send(destination, new MessageCreator() { 
                public Message createMessage(Session session) throws JMSException { 
                    return session.createTextMessage(message); 
                } 
            }); 
        }  
     
        public JmsTemplate getJmsTemplate() { 
            returnjmsTemplate; 
        }  
     
        @Resource 
        public void setJmsTemplate(JmsTemplate jmsTemplate) { 
            this.jmsTemplate = jmsTemplate; 
        } 
      
    } 

       We can see that in the body of the sendMessage method, we send messages to the corresponding Destination through jmsTemplate. At this point, we are configured to generate a simple text message and send it to the producer of the specified destination Destination.
1.2.4 Configure the consumer After the

producer sends a message to the specified destination Destination, the next step is for the consumer to consume the message from the specified destination. So how does the consumer know that a producer has sent a message to the specified destination Destination? This is achieved through the MessageListenerContainer, a message listener container encapsulated by Spring, which is responsible for receiving information and distributing the received information to the real MessageListener for processing. Each consumer needs a corresponding MessageListenerContainer for each destination. For the message monitoring container, in addition to knowing which destination to listen to, it also needs to know where to listen, that is to say, it also needs to know which JMS server to listen to. This is done by injecting a message when configuring the MessageConnectionFactory. ConnectionFactory to achieve. So when we configure a MessageListenerContainer, there are three properties that must be specified, one is the ConnectionFactory that indicates where to listen from; the other is the Destination that indicates what to listen for; the other is the MessageListener that processes the message after receiving the message. Spring provides us with two types of MessageListenerContainer, SimpleMessageListenerContainer and DefaultMessageListenerContainer.

SimpleMessageListenerContainer will create a session and consumer Consumer at the beginning, and will use the standard JMS MessageConsumer.setMessageListener() method to register the listener to let the JMS provider call the listener's callback function. It does not dynamically adapt to runtime needs and participate in external transaction management. Compatibility-wise, it is very close to the stand-alone JMS specification, but generally not compatible with the JMS limitations of Java EE.

In most cases, we still use DefaultMessageListenerContainer. Compared with SimpleMessageListenerContainer, DefaultMessageListenerContainer dynamically adapts to runtime needs and can participate in external transaction management. It is a good balance of low requirements on the JMS provider, advanced features such as transaction participation and compatibility with the Java EE environment.

Defining a MessageListener

       that handles messages To define a MessageListener that handles messages, we only need to implement the MessageListener interface in the JMS specification. There is only one method in the MessageListener interface, the onMessage method, which is automatically called when a message is received.


Java code Collection code

    package com.tiantian.springintejms.listener; 
      
    import javax.jms.JMSException; 
    import javax.jms.Message; 
    import javax.jms.MessageListener; 
    import javax.jms.TextMessage; 
      
    public class ConsumerMessageListener implements MessageListener { 
      
        public void onMessage(Message message) { 
            //Here we know that the producer sends a plain text message, so we can directly cast 
            TextMessage textMsg = (TextMessage) message ; 
            System.out.println("A plain text message was received."); 
            try { 
                System.out.println("The message is: " + textMsg.getText()); 
            } catch (JMSException e) { 
                e.printStackTrace (); 
            } 
        } 
      
    } 



       With MessageListener, we can configure a message listener container in Spring's configuration file.
Xml code Collection code

    <!--This is the queue destination--> 
    <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue"> 
        <constructor-arg> 
            <value>queue</value> 
        </constructor-arg> 
    </bean> 
    <!-- 消息监听器 --> 
    <bean id="consumerMessageListener" class="com.tiantian.springintejms.listener.ConsumerMessageListener"/>     
     
    <!-- 消息监听容器 --> 
    <bean id="jmsContainer"        class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
        <property name="connectionFactory" ref="connectionFactory" /> 
        <property name="destination" ref="queueDestination" /> 
        <property name="messageListener" ref="consumerMessageListener" /> 
    </bean> 

 

       We can see that we have defined an ActiveMQQueue destination named queue, and our listener is listening for messages sent to this destination.

       So far our generators and consumers have been configured, which means that our integration has been completed. At this time, the complete Spring configuration file should look like this:
Xml code Collection code

    <?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:context="http://www.springframework.org/schema/context" 
        xmlns:jms="http: //www.springframework.org/schema/jms" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans-3.0. xsd 
         http://www.springframework.org/schema/context 
         http://www.springframework.org/schema/context/spring-context-3.0.xsd 
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring- beans-3.0.xsd 
        http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd"> 
      
        <context:component-scan base-package ="com.tiantian" /> 
      
        <!-- The JMS tool class provided by Spring, which can send and receive messages --> 
        <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" > 
            <!-- This connectionFactory corresponds to the ConnectionFactory object we defined by Spring --> 
            <property name="connectionFactory" ref="connectionFactory"/>   
        </bean> 
         
        <!-- The ConnectionFactory that can really generate Connection is provided by the corresponding JMS service vendor--> 
        <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
            <property name="brokerURL" value=" tcp://localhost:61616"/> 
        </bean> 
         
        <!-- Spring's ConnectionFactory to manage the real ConnectionFactory --> 
        <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory" > 
            <!-- The target ConnectionFactory corresponds to the real ConnectionFactory that can generate JMS Connection --> 
            <property name="targetConnectionFactory" ref="targetConnectionFactory"/> 
        </bean> 
         
        <!--This is the queue destination--> 
        <bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue"> 
            <constructor-arg> 
                <value>queue</value> 
            </constructor-arg> 
        </bean> 
        <!-- 消息监听器 --> 
        <bean id="consumerMessageListener" class="com.tiantian.springintejms.listener.ConsumerMessageListener"/> 
        <!-- 消息监听容器 --> 
        <bean id="jmsContainer" 
            class="org.springframework.jms.listener.DefaultMessageListenerContainer"> 
            <property name="connectionFactory" ref="connectionFactory" /> 
            <property name="destination" ref="queueDestination" /> 
            <property name="messageListener" ref="consumerMessageListener" /> 
        </bean> 
    </beans> 





       Let's test to see if our integration is really successful. The test code is as follows:


Java code Collection code

    package com. tiantian.springintejms.test; 
      
    import javax.jms.Destination; 
      
    import org.junit.Test; 
    import org.junit.runner.RunWith; 
    import org.springframework.beans.factory.annotation.Autowired; 
    import org.springframework.beans.factory .annotation.Qualifier; 
    import org.springframework.test.context.ContextConfiguration; 
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
    import com.tiantian.springintejms.service.ProducerService;   
      
    @RunWith(SpringJUnit4ClassRunner.class) 
    @ContextConfiguration("/applicationContext.xml") 
    public class ProducerConsumerTest { 
      
        @Autowired 
        private ProducerService producerService; 
        @Autowired 
        @Qualifier("queueDestination") 
        private Destination destination; 
         
        @Test 
        public void testSend() { 
            for ( int i=0; i<2; i++) { 
                producerService.sendMessage(destination, "Hello, producer! This is the message: " + (i+1)); 
            } 
        } 
         
    } 



       In the above test code we use the production The consumer sent two messages, which normally should be received by the consumer. After running the test code, the console output is as follows:





       Look, the console has produced the correct output, which means that our integration has indeed been successful.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326990260&siteId=291194637