Spring integrates JMS ---- implementation based on ActiveMQ

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. Import jar package:


Xml code Collection code

    <dependencies> 
            <dependency> 
                <groupId>junit</groupId> 
                <artifactId>junit</artifactId> 
                <version>4.10</version> 
                <scope>test</scope> 
            </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> 
bat 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, 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"/> 



       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 has to be The JMS service provider provides and needs to inject it 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 look like this:
Xml Code Collection Code

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



       ActiveMQ provides us with a PooledConnectionFactory, which can be used to pool Connection, Session and MessageProducer by injecting an ActiveMQConnectionFactory into it, 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> 
        <bean id="pooledConnectionFactory" class="org.apache.activemq. pool.PooledConnectionFactory"> 
            <property name="connectionFactory" ref="targetConnectionFactory"/> 

        </bean> 
        <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"> 
            <property name="targetConnectionFactory" ref="pooledConnectionFactory"/> 
        </bean> 






1.2.3 Configure producer

configuration After the ConnectionFactory is ready, we need to configure the producer. The producer is responsible for generating the message and sending it to the JMS server, which usually corresponds to one of our business logic service implementation classes. But how does our service implementation class send messages? This is usually achieved by using the JmsTemplate class provided by Spring, so the core of configuring the producer is to configure the JmsTemplate for message sending. For the message sender, it needs to know where to send the message when it sends the message. For this reason, when we define the JmsTemplate, we need to inject a ConnectionFactory object provided by Spring into it.
Xml code Collection code

    <!-- The JMS tool class provided by Spring, it can send and receive messages, etc.--> 
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> 
        <! 
        <property name="connectionFactory" ref="connectionFactory"/> 
    </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< 

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




   defines a ProducerService to send plain text messages to Destination:


Java code collection code

    import javax.jms.Destination; 
     
    public interface ProducerService { 
     
         public void sendMessage(Destination destination, final String message); 
    } 






Java code collection Code

    import javax.jms.Destination; 
    import javax.jms.JMSException; 
    import javax.jms.Message; 
    import javax.jms.Session; 
    import org.springframework.beans.factory.  annotation.Autowired; 
    import org.springframework.jms.core.JmsTemplate; 
    import org.springframework.jms.core.MessageCreator; 
    import org.springframework.stereotype.Service; 
     
    import cn.tzz.jms.activemq.spring.ProducerService; 
      
      
    @Service 
    public class ProducerServiceImpl implements ProducerService { 
      
        @Autowired 
        private JmsTemplate jmsTemplate; 
         
        public void sendMessage(Destination destination, final String message) { 
            System.out.println("生产者发消息:" + message); 
            jmsTemplate.send(destination, new MessageCreator() { 
                public Message createMessage(Session session) throws JMSException { 
                    return session.createTextMessage(message); 
                } 
            }); 
        }  
    } 





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

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

    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 Knowing that what the producer sent is a plain text message, so you can directly cast it here 
            TextMessage textMsg = (TextMessage) message; 
            try { 
                System.out.println("\t\tMessage received: " + 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

    <!-- Message listener--> 
        <bean id="consumerMessageListener" class="cn.tzz.jms.activemq.spring.ConsumerMessageListener"/>     
        <!-- Message listener container--> 
        <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 We define 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

    <context:annotation-config /> 
        <context:component-scan base-package="package cn.tzz.jms.activemq.spring" /> 
         
        < !-- ActiveMQ --> 
        <!-- ConnectionFactory that can really generate Connection, provided by the corresponding JMS service vendor --> 
        <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> 
            <property name="brokerURL" value="tcp://localhost:61616"/> 
        </bean> 
        <bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"> 
            <property name="connectionFactory" ref="targetConnectionFactory"/> 
            <property name="maxConnections" value="10"/> 
        </bean> 
        <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory"> 
            <property name="targetConnectionFactory" ref="pooledConnectionFactory"/>          <!-- The JMS tool class provided by Spring, which can send and receive messages --> 
        </bean> 
         
     

        <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> 
        <!--Message queue destination, peer-to-peer --> 
        <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> 
         
         
        <!-- 消息监听器 --> 
        <bean id="consumerMessageListener" class="cn.tzz.jms.activemq.spring.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> 





测试:


Java代码  收藏代码

    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 cn.tzz.jms.activemq.spring.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 < 5; i++) { 
                producerService.sendMessage(destination, "message--" + i); 
            } 
        } 
    } 





   In the above test code, we use the producer to send 5 The consumer should be able to receive both messages. After running the test code, the console output is as follows:

Producer sends message: message --0

Receives message: message --0

Producer sends message: message--1

Receives message: message--1

Producer sends message: message- -2

Received message: message--2

Producer sent message: message--3

Received message: message--3

Producer sent message: message--4

Received message: message--4

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326487414&siteId=291194637