首先和大家一起回顾一下JMS服务:
- 消息服务:一个中间件,用于解决两个活多个程序之间的耦合,底层由Java 实现。
- 优势:异步、可靠
- 消息模型:点对点,发布/订阅
- JMS中的对象
事前说明:
这里和大家讲解一下这个配置文件,如果大家能够从上述配置文件中看懂,可以跳过。同学们也可以在ActiveMQ官网中的查看。
ActiveMq 中的DTD,我们在声明相关配置之前,我们需要先导入ActiveMq 中的DTD,不然Spring 并不理解我们的标签是什么意思。
http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd
1 我们在pom.xml 文件中有配置了activemq 的版本依赖我们这里的版本,需要和依赖的版本一样,不然是找不到相关的dtd
2、amq:connectionFactory:很直白的一个配置项,用于配置我们链接工厂的地址和用户名密码,这里需要注意的是选择tcp连接而不是http连接
3、jmsTemplate:比较重要的一个配置,这里指定了连接工厂,默认消息发送目的地,还有连接时长,发布消息的方式
maven工程添加依赖
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- ActiveMQ依赖 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
<!-- 加入spring-jms依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
</dependencies>
一、创建生产者: applicationContext-activemq-topic-producer.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://xxx.xxx.xxx.xxx:61616"/>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
</bean>
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory"/>
<!-- 订阅模式 -->
<property name="pubSubDomain" value="true"/>
</bean>
<!--订阅模式,一对多 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic.item"/>
</bean>
</beans>
二、创建消费者1 applicationContext-activemq-topic-consumer1.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://xxx.xxx.xxx.xxx:61616"/>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<!-- 消费者标识 -->
<property name="clientId" value="topic-consumer-a"/>
</bean>
<!--订阅模式,一对多的 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic.item"/>
</bean>
<!-- messageListener实现类 -->
<bean id="topicMessageListener1" class="it.hehe.spring.topic.TopicMessageListener1"/>
<!-- 配置一个jms监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="topicDestination"/>
<property name="messageListener" ref="topicMessageListener1"/>
<!-- 消息持久化 -->
<property name="subscriptionDurable" value="true"/>
<!-- 消费者标识 -->
<property name="clientId" value="topic-consumer-a"/>
<!-- 订阅者标识(与消费者标识符可以不一样;默认为监听器全限定名) -->
<property name="durableSubscriptionName" value="topic-consumer-a"/>
<!-- 设置为发布/订阅模式 -->
<property name="pubSubDomain" value="true"/>
<!-- 是否开启事务 -->
<property name="sessionTransacted" value="false"/>
<!-- 客户端消息确认模式名称 -->
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>
</beans>
二、创建消费者2 applicationContext-activemq-topic-consumer2.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://xxx.xxx.xxx.xxx:61616"/>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
<!-- 消费者标识 -->
<property name="clientId" value="topic-consumer-b"/>
</bean>
<!--订阅模式,一对多的 -->
<bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="topic.item"/>
</bean>
<!-- messageListener实现类 -->
<bean id="topicMessageListener2" class="it
.hehe.spring.topic.TopicMessageListener2"/>
<!-- 配置一个jms监听容器 -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="topicDestination"/>
<property name="messageListener" ref="topicMessageListener2"/>
<!-- 消息持久化 -->
<property name="subscriptionDurable" value="true"/>
<!-- 消费者标识 -->
<property name="clientId" value="topic-consumer-b"/>
<!-- 订阅者标识(与消费者标识符可以不一样;默认为监听器全限定名) -->
<property name="durableSubscriptionName" value="topic-consumer-b"/>
<!-- 设置为发布/订阅模式 -->
<property name="pubSubDomain" value="true"/>
<!-- 是否开启事务 -->
<property name="sessionTransacted" value="false"/>
<!-- 客户端消息确认模式名称 -->
<property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>
三、创建消费者2监听器类
TopicMessageListener2.java
package cn.itcast.activemq.spring.topic;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener;
public class TopicMessageListener2 extends AbstractAdaptableMessageListener {
@Override
public void onMessage(Message message, Session session) throws JMSException {
// 判断消息类型是TextMessage
if (message instanceof TextMessage) {
// 如果是,则进行强转
TextMessage textMessage = (TextMessage) message;
try {
// 消费消息,打印消息内容
String text = textMessage.getText();
System.out.println("TopicMessageListener2-消费者2消息监听器接收到消息;消息内容为:" + text);
} catch (Exception e) {
e.printStackTrace();
}
/**
* 在spring的配置文件配置监听容器的时候如果 AcknowledgeMode配置为CLIENT_ACKNOWLEDGE的话:
* 那么在监听器代码中抛出异常或者执行session.recover();则会将信息重新发送6次(默认每秒发一个消息)
* 在重发6次后消息还是处理失败,那么消息将自动到DLQ-死信队列(Dead Letter Queue用来保存处理失败或者过期的消息;
* 默认在ActiveMQ队列里面的名称为:ActiveMQ.DLQ)
*/
session.recover();
/**
* 什么时候会重发:
* Messages are redelivered to a client when any of the following occurs:
A transacted session is used and rollback() is called.
A transacted session is closed before commit() is called.
A session is using CLIENT_ACKNOWLEDGE and Session.recover() is called.
*/
}
}
}
四、创建消费者1监听器类
TopicMessageListener1.java
package cn.itcast.activemq.spring.topic;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener;
public class TopicMessageListener1 extends AbstractAdaptableMessageListener {
@Override
public void onMessage(Message message, Session session) throws JMSException {
// 判断消息类型是TextMessage
if (message instanceof TextMessage) {
// 如果是,则进行强转
TextMessage textMessage = (TextMessage) message;
try {
// 消费消息,打印消息内容
String text = textMessage.getText();
System.out.println("TopicMessageListener1-消费者1 消息监听器接收到消息;消息内容为:" + text);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
五、创建测试生产者类
Producer.java
package cn.itcast.activemq.spring.topic;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class Producer {
public static void main(String[] args) {
// 创建spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-activemq-topic-producer.xml");
// 从spring容器中获取JMSTemplate,这个对象是用于发送消息的
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
//创建消息模式
Destination destination = (Destination)context.getBean("topicDestination");
// 使用JMSTemplate发送消息
jmsTemplate.send(destination, new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = new ActiveMQTextMessage();
textMessage.setText("。---spring-topic的方式发送。订阅主题的名称为:topic.item");
System.out.println("已发送消息...");
return textMessage;
}
});
}
}
六、分别创建消费者测试类1、2
package cn.itcast.activemq.spring.topic;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Consumer1 {
public static void main(String[] args) {
// 创建spring容器
new ClassPathXmlApplicationContext("applicationContext-activemq-topic-consumer1.xml");
}
}
package cn.itcast.activemq.spring.topic;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Consumer2 {
public static void main(String[] args) {
// 创建spring容器
new ClassPathXmlApplicationContext("applicationContext-activemq-topic-consumer2.xml");
}
}