Introduction to JMS
The full name of JMS is the Java message Service, the Java messaging Services. It is mainly used for messaging between producers and consumers, producers are responsible for generating messages, and consumers are responsible for receiving messages. Applying it to the actual business requirements, we can use the producer to generate a message and send it at a specific time, and the corresponding customer receives the corresponding message to complete the corresponding business logic. There are two types of message delivery, one is point-to-point, one producer and one consumer, the other is the Publish/subscribe model, where a producer generates messages and sends them, which can be received by multiple consumers. Spring Consolidated 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, we need to have a concrete implementation when we use it, we use the ACTIVEMQ of Apache as its implementation. The dependencies used are managed using MAVEN, depending on the following:
<dependencies> <dependency> <groupId>junit</groupId> <artifacti
D>junit</artifactid> <version>4.10</version> <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> &L
T;/dependency> <dependency> <groupId>javax.annotation</groupId> <artifactid>jsr250-api&
lt;/artifactid> <version>1.0</version> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <ARTIFACTID>ACTIVEMQ-CORE</ARTIFACTID&G
T
<version>5.7.0</version> </dependency> </dependencies>
Activemq Ready
Since it is the use of Apache ACTIVEMQ as a JMS implementation, then first we should go to the Apache online download activemq (http://activemq.apache.org/ download.html), after decompression run its bin directory under the Activemq.bat file start Activemq. Configure ConnectionFactory
ConnectionFactory is used to generate links to JMS servers, Spring provides us with a number of connectionfactory, There are singleconnectionfactory and cachingconnectionfactory. Singleconnectionfactory the request to establish a JMS server link always returns the same link and ignores the connection Close method call. Cachingconnectionfactory inherits Singleconnectionfactory, so it has all the features of Singleconnectionfactory, and it also has new caching capabilities, which caches session, MessageProducer and Messageconsumer. Here we use Singleconnectionfactory as an example.
<bean id= "ConnectionFactory" class= "Org.springframework.jms.connection.SingleConnectionFactory"/>
Does this define the connectionfactory that produces the JMS server link? The answer is right and wrong. Spring provides the connectionfactory only spring for managing ConnectionFactory, and the connectionfactory that actually generate the JMS server link is provided by the JMS service vendor, And it needs to be injected into the connectionfactory provided by spring. We are using JMS implemented by ACTIVEMQ, so the real connection we can produce here should be the connectionfactory provided by ACTIVEMQ. So the complete code that defines a connectionfactory should look like this:
<!--can actually generate connection connectionfactory, provided by the corresponding JMS service vendor--> <bean id= "targetconnectionfactory" class= "
Org.apache.activemq.ActiveMQConnectionFactory ">
<property name=" Brokerurl "value=" tcp://localhost : 61616 "/>
</bean>
<!--spring is used to manage the real connectionfactory connectionfactory-->
<bean Id= "ConnectionFactory" class= "Org.springframework.jms.connection.SingleConnectionFactory" >
<!-- The target connectionfactory corresponds to the real connectionfactory--> <property name= "that can produce the JMS connection.
" Targetconnectionfactory "ref=" targetconnectionfactory "/>
</bean>
ACTIVEMQ provides us with a pooledconnectionfactory, by injecting a activemqconnectionfactory into the inside that can be used to connection, Session and MessageProducer pool, this can greatly reduce our resource consumption. When using pooledconnectionfactory, we should define a connectionfactory as follows:
<!--can actually generate connection connectionfactory, 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= "ten"/>
</bean>
< Bean id= "ConnectionFactory" class= "Org.springframework.jms.connection.SingleConnectionFactory" >
< Property Name= "Targetconnectionfactory" ref= "pooledconnectionfactory"/>
</bean>
Configure producers
After the ConnectionFactory is configured, we need to configure the producer. The producer is responsible for generating messages and sending them 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 done using the Jmstemplate class that spring provides for us, so configuring the producer is essentially configuring the jmstemplate to send messages. For a message sender, it knows where to send the message, so we need to inject a spring-provided connectionfactory object into the definition of jmstemplate.
<!--the JMS tool class provided by spring, which can send, receive, etc.-->
<bean id= "jmstemplate" class= " Org.springframework.jms.core.JmsTemplate ">
<!-- This connectionfactory corresponds to the ConnectionFactory object that we defined spring provides--> <property name= "ConnectionFactory"
ConnectionFactory "/>
</bean>
When we really use jmstemplate to send messages, we need to know the destination of the message sent, that is, destination. In JMS there is a destination interface to represent the destination, which has no method definition, but is used to make a logo . The default destination is used when we do not specify destination when using Jmstemplate for message delivery. The default destination can be injected by property defaultdestination or Defaultdestinationname when defining a jmstemplate bean object. Defaultdestinationname corresponds to an ordinary string. Two types of destination are implemented in ACTIVEMQ, one is point-to-point activemqqueue and the other is activemqtopic that supports subscription/publish mode. When defining both types of destination, we can construct them through a Name property, such as:
<!--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 theme destination, a one-to-many-->
<bean id= "topicdestination" class= " Org.apache.activemq.command.ActiveMQTopic ">
<constructor-arg value=" topic "/>
</bean>
Suppose we define a producerservice that has a method to send a plain text message to destination SendMessage, then our code is probably like this:
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 ("---------------producer sends the elimination
Interest-----------------");
System.out.println ("---------------producer sent a message:" + messages); Jmstemplate.send (Destination, new Messagecreator () {public message CreateMessage (sessions session) throws Jmse
Xception {return session.createtextmessage (message);
}
}); } public Jmstemplate GetjmstEmplate () {returnjmstemplate;
@Resource public void Setjmstemplate (Jmstemplate jmstemplate) {this.jmstemplate = jmstemplate;
}
}
We can see in the SendMessage method body that we are sending messages through Jmstemplate to the corresponding destination. Here, we generate a simple text message and send it to the designated destination destination producer is configured.
Configure Consumers
After the producer sends a message to the designated destination destination, the consumer then consumes the message of the specified destination. So how do consumers know that a producer sends a message to a named destination destination? This is the listener container for our encapsulated message through springMessagelistenercontainerImplemented, it is responsible for receiving the information and distributing the received information to the real messagelistener for processing. Each consumer corresponds to each destination with a correspondingMessagelistenercontainer。 For message listening containers, in addition toto know which destination to monitor, you need to know where to listen ., which means it alsoneed to know which JMS server to listen to, which is passed in the configurationmessageconnectionfactory into the inside of a connectionfactory to achieve. So when we configure a messagelistenercontainer, there are three attributes that must be specified, one to indicate where to listen connectionfactory, and one to indicate what to listen to destination A messagelistener that receives message processing after it has been received. Spring altogether provides us with two types of Messagelistenercontainer,simplemessagelistenercontainer and Defaultmessagelistenercontainer.
Simplemessagelistenercontainer will be inCreate a conversation session and consumer consumer at the beginningand will use the standard JMSMessageconsumer.setmessagelistener ()Method registers the listener so that the JMS provider invokes the listener's callback function. It does not dynamically adapt to run-time needs and participates in external transaction management. compatibility, it is very close to the stand-alone JMS specification, but is generally incompatible with the JMS restrictions of Java EE.
In most cases, we still useDefaultmessagelistenercontainer, compared to Simplemessagelistenercontainer, Defaultmessagelistenercontainer will dynamically adapt to run-time needs and be able to participate in external transaction management。 It balances the demand for JMS providers with low, advanced functionality such as transactional participation and a compatible Java EE environment.
Define MessageListener for processing messages
To define the MessageListener for processing messages we only need to implement the MessageListener interface in the JMS specification. There is only one method OnMessage method in the MessageListener interface, which is automatically invoked when a message is received.
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 is sending a plain text message, so it is possible to cast
textmessage textmsg = (textmessage) messages directly;
System.out.println ("received a plain text message.") ");
try {
System.out.println ("Message content is:" + textmsg.gettext ());
} catch (JMSException e) {
e.printstacktrace () ;
}
}
}
With MessageListener, we can configure a message listening container in the spring configuration file.
<!--This is the queue destination-->
<bean id= "queuedestination" class= "Org.apache.activemq.command.ActiveMQQueue" >
<constructor-arg>
<value>queue</value>
</constructor-arg>
</bean >
<!--message listener-->
<bean id= "Consumermessagelistener" class= " Com.tiantian.springintejms.listener.ConsumerMessageListener "/>
<!--message monitoring container-->
<bean id=" Jmscontainer " class=" Org.springframework.jms.listener.DefaultMessageListenerContainer ">
< Property Name= "ConnectionFactory" ref= "ConnectionFactory"/> <property name= "Destination"
Queuedestination "/>
<property name= messagelistener" ref= "Consumermessagelistener"/>
Bean>
We can see that we have defined a activemqqueue destination named queue, and our listener is listening for messages sent to this destination.
Now that our generators and consumers are configured, this means that our integration is complete. This time the complete spring configuration file should be like this:
<?xml version= "1.0" encoding= "UTF-8"?> <beans "xmlns=" 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/co ntext 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 "/> <!--Spring provides a JMS utility class that can perform message sending, receiving, and so on--> <bean id=" jmstemplate "class=" Org.springframe Work.jms.core.JmsTemplate "> <!--this connectionFactory corresponds to the ConnectionFactory object that we defined spring provides--> <property name= "ConnectionFactory" ref= "/> </bean> <!--can actually produce connection connectionfactory, provided by the corresponding JMS service vendor--> <bean id=" Targetconne Ctionfactory "class=" org.apache.activemq.ActiveMQConnectionFactory "> <property name=" brokerurl "value=" tcp:/ /localhost:61616 "/> </bean> <!--spring is used to manage the real connectionfactory connectionfactory--> <bean Id= "ConnectionFactory" class= "Org.springframework.jms.connection.SingleConnectionFactory" > <!--target connectio Nfactory corresponds to the real connectionfactory--> <property name= "targetconnectionfactory" ref= "that can produce JMS connection TargetCo Nnectionfactory "/> </bean> <!--This is the queue destination--> <bean id=" queuedestination "class=" org.apache.ac Tivemq.command.ActiveMQQueue "> <constructor-arg> <value>queue</value>
;/constructor-arg> </bean> <!--message listener--> <bean id= "Consumermessagelistener" class= "Com.tiantian.springintejms.liste" Ner. Consumermessagelistener "/> <!--message monitoring container--> <bean id=" Jmscontainer "class=". Jms.listener.DefaultMessageListenerContainer "> <property name=" connectionfactory "ref=" ConnectionFactory "/&"
Gt <property name= "Destination" ref= "queuedestination"/> <property name= "MessageListener" ref= "consumerMess"
Agelistener "/> </bean> </beans>
Then let's test to see if our integration really worked, and the test code was as follows:
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 Producers. This is the message: "+ (i+1));}}}
.