JMS简介
JMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中的话我们可以在特定的时候利用生产者生成一消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。对于消息的传递有两种类型,一种是点对点的,即一个生产者和一个消费者一一对应;另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。
消息的两种传播方式
JMS支持两种消息传播:PTP 和 PUB/SUB
-
PTP :点对点发送。消息的发送方将消息放入管道中,消息的接收方从管道中取出消息并处理。
-
PUB/SUB :发布/订阅方式。消息的发布者将自己的主题放入消息中心,同时进行消息投递,消息订阅者只获取自己订阅的消息。
jms为了支持上述两种模式,提供了两套针对同样接口的实现,对照关系如下:
-
ConnectionFacatory:被管理的对象,由客户端(发布者/接受者)使用,用来创建一个链接。
-
Connection:提供一个JMS消息的活动链接。
-
Destination:封装了消息目的地,或者主题类型。
-
Session:一个用来发送和接受消息的线上上下文。
-
MessageProducer:由session创建的,用来发送消息的对象。
-
MessageConsumer:由session创建的用来接受消息的对象。
Spring整合JMS
服务端直接用docker进行部署,脚本如下:
docker run --name activemq8161 -d \
-p 61616:61616 \
-p 8161:8161 \
-v `pwd`/conf:/opt/activemq/conf \
-v `pwd`/data:/opt/activemq/data \
webcenter/activemq
客户端所需要的pom依赖:
<!-- Spring start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</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-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring end -->
<!-- ActiveMQ Start -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-kahadb-store</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-spring</artifactId>
<version>${activemq.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.jms/javax.jms-api -->
<dependency>
<groupId>javax.jms</groupId>
<artifactId>javax.jms-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- ActiveMQ end -->
spring引入jms activeMQ配置文件:
<?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:jms="http://www.springframework.org/schema/jms"
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">
<!-- JMS ActiveMQ -->
<bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${org.jeemp.activemq.brokerURL}" />
<property name="userName" value="${org.jeemp.activemq.userName}" />
<property name="password" value="${org.jeemp.activemq.password}" />
</bean>
<bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="activeMQConnectionFactory" />
</bean>
<!-- Spring JmsTemplate 的消息生产者 start-->
<bean id="seriaMessageConverter" class="org.jeemp.jms.SeriaMessageConverter">
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="messageConverter" ref="seriaMessageConverter" />
</bean>
<bean id="jmsPubSubDomainTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="messageConverter" ref="seriaMessageConverter" />
<property name="pubSubDomain" value="true" />
</bean>
<!--Spring JmsTemplate 的消息生产者 end-->
<!-- JMS Listener -->
<!-- 消费者 start -->
<!-- 定义Queue监听器 -->
<jms:listener-container connection-factory="cachingConnectionFactory" message-converter="seriaMessageConverter"
destination-type="queue">
<jms:listener destination="test.queue" ref="activemq" method="receiveQueueMessage"
concurrency="100" />
<jms:listener destination="test.queue" ref="activemq_topic" method="receiveQueueMessage"
concurrency="100" />
</jms:listener-container>
<!-- 定义Topic监听器 -->
<jms:listener-container connection-factory="activeMQConnectionFactory" message-converter="seriaMessageConverter"
destination-type="topic">
<jms:listener destination="test.topic" ref="activemq" method="receiveTopicMessage"
concurrency="100" />
<jms:listener destination="test.topic" ref="activemq_topic" method="receiveTopicMessage"
concurrency="100" />
</jms:listener-container>
<!-- 消费者 end -->
<bean id="activemq" class="org.jeemp.activemq.ActiveMQAction">
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="jmsPubSubDomainTemplate" ref="jmsPubSubDomainTemplate"/>
</bean>
<bean id="activemq_topic" class="org.jeemp.activemq.ActiveMQTopicAction">
<property name="jmsTemplate" ref="jmsTemplate"/>
<property name="jmsPubSubDomainTemplate" ref="jmsPubSubDomainTemplate"/>
</bean>
</beans>
创建测试类验证:
package org.jeemp.activemq;
import org.jeemp.web.BaseAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.JmsTemplate;
public class ActiveMQAction extends BaseAction {
private Logger logger = LoggerFactory.getLogger(ActiveMQAction.class);
private JmsTemplate jmsTemplate;
private JmsTemplate jmsPubSubDomainTemplate;
public void setJmsPubSubDomainTemplate(JmsTemplate jmsPubSubDomainTemplate) {
this.jmsPubSubDomainTemplate = jmsPubSubDomainTemplate;
}
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void sendQueueMessage() {
jmsTemplate.convertAndSend("test.queue","测试消息队列点对点模式");
}
public void sendTopicMessage() {
jmsPubSubDomainTemplate.convertAndSend("test.topic","测试消息队列订阅模式");
}
public void receiveQueueMessage(String message) {
logger.info("消息队列Queue接收到的消息1:"+message);
}
public void receiveTopicMessage(String message) {
logger.info("消息队列Topic接收到的消息1:"+message);
}
}
因为需要验证点对点模式和订阅模式,所以需要创建两个测试类,监听相同的方法:
package org.jeemp.activemq;
import org.jeemp.web.BaseAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.core.JmsTemplate;
public class ActiveMQTopicAction extends BaseAction {
private Logger logger = LoggerFactory.getLogger(ActiveMQAction.class);
private JmsTemplate jmsTemplate;
private JmsTemplate jmsPubSubDomainTemplate;
public void setJmsPubSubDomainTemplate(JmsTemplate jmsPubSubDomainTemplate) {
this.jmsPubSubDomainTemplate = jmsPubSubDomainTemplate;
}
public void setJmsTemplate(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void receiveQueueMessage(String message) {
logger.info("消息队列Queue接收到的消息2:"+message);
}
public void receiveTopicMessage(String message) {
logger.info("消息队列Topic接收到的消息2:"+message);
}
}
启动tomcat,运行
http://localhost:8080/activemq/sendQueueMessage.json
控制台显示结果:
我们同样测试下订阅的模式:
http://localhost:8080/activemq/sendTopicMessage.json
控制台显示结果: