一、基础学习
首先导入pom依赖
<!-- activemq -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.11.0</version>
</dependency>
<!--jmsTemplate -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
1.发送和接收队列(Queue)消息
发送
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Sender {
public static void main(String[] args) {
// 连接工厂
ConnectionFactory connectionFactory= new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");;
//JMS 客户端到JMS Provider 的连接
//发送消息的是生产者producer mq的服务器是提供者provider 接受消息的是消费者
Connection connection = null;
// Session: 一个发送或接收消息的线程
//可以设置事务和确认方式
Session session = null;
// Destination :消息的目的地;消息发送给谁.
//可以是一个topic 也可以是一个queue
Destination destination;
// MessageProducer:消息生产者
MessageProducer producer;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();
// 启动
connection.start();
//createSession 第一个参数transacted 表示是否支持事务
//第二个参数 acknowledgeMode 有如下几种
//1.AUTO_ACKNOWLEDGE 自动确认模式,不需客户端进行确认
//2.CLIENT_ACKNOWLEDGE 客户端进行确认
//客户端获得message之后需要进行message.acknowledge();
//3.DUPS_OK_ACKNOWLEDGE 允许重复消息
session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
// 创建队列名为FirstQueue的目的地
destination = session.createQueue("FirstQueue");
// 创建将消息发送到该目的地的消息生产者
producer = session.createProducer(destination);
// 持久化模式 NON_PERSISTENT不持久化,PERSISTENT持久化
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
TextMessage message = session
.createTextMessage("ActiveMq 发送的消息");
// 发送消息到目的地方
producer.send(message);
//也可以这样
//producer.send(
// message,//要发送的消息
// DeliveryMode.NON_PERSISTENT,//是否持久化
// 1,//消息优先级 1-4位普通消息,5-9位加急消息,不严格按照优先级发送,但会保证加急消息优先发送 默认级别为4
// 1000L//消息过期时间,默认永不过期,单位毫秒
// );
System.out.println("发送消息***");
session.commit();
} catch (Exception e) {
try {
if(null != session){
session.rollback();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
}
接收
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class Receiver {
public static void main(String[] args) {
ConnectionFactory connectionFactory;
Connection connection = null;
Session session;
Destination destination;
MessageConsumer consumer;
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("FirstQueue");
consumer = session.createConsumer(destination);
while (true) {
//设置接收者接收消息的时间,
TextMessage message = (TextMessage) consumer.receive(1000);
if (null != message) {
//如果生产者设置消息确认模式为CLIENT_ACKNOWLEDGE 则需要客户端进行确认
/*
try {
message.acknowledge();
} catch (Exception e) {
//确认消息过程中发生异常进行处理
}
*/
System.out.println("收到消息:" + message.getText());
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection){
connection.close();
}
} catch (Throwable ignore) {
}
}
}
}
先启动接收的方法,然后启动发送的方法得到如下结果
这是同步获取消息,也可以这样设置监听来异步获取消息
consumer.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
try {
System.out.println("收到消息:" + ((TextMessage)message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
while(true){
Thread.sleep(1000);
}
2.发送和接收主题(Topic)消息
只要将destination改为
destination = session.createTopic("FirstTopic");
即可。
Topic和Queue都是属于Destination的一种,创建连接的时候也可以直接创建发送Queue消息或Topic消息的的连接工厂
TopicConnectionFactory factory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, BROKER_URL);
TopicConnection connection = factory.createTopicConnection();
connection.start();
TopicSession session = connection.createTopicSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
将Topic改为Queue也是一样的
TopicSession可以创建发布者Publisher和订阅者Subscriber,其中Publisher属于Producer,Subscriber属于Consumer
3.使用JmsTemplate
以下以Queue为模板,Topic的话只要把Destination缓存Topic就可以了
发送消息
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
public class TemplateSender{
public static void main(String[] args) {
/*
* 这些可以写在spring配置文件中,使用时直接获取jmsTemplate这个bean就可以
*/
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(connectionFactory);
jmsTemplate.setDefaultDestination(new ActiveMQQueue("queue1"));
jmsTemplate.setReceiveTimeout(1000);
//发送消息
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("aaa", "value1");
mapMessage.setBoolean("bbb", true);
return mapMessage;
}
});
System.out.println("发送消息");
}
}
同步接收消息
import java.util.Map;
import javax.jms.ConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsTemplate;
public class TemplateReceiver {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(connectionFactory);
jmsTemplate.setDefaultDestination(new ActiveMQQueue("queue1"));
jmsTemplate.setReceiveTimeout(1000);
//同步接收消息
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Map<String, Object> message = (Map<String,Object>) jmsTemplate.receiveAndConvert();
if(message != null){
System.out.println(message.get("aaa"));
System.out.println(message.get("bbb"));
}
}
}
}
异步接收消息,要用到MessageListenerContainer
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
public class ContainerReceiver {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");
//异步接收消息
DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setDestination(new ActiveMQQueue("queue1"));
container.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
if (message != null) {
MapMessage map = (MapMessage) message;
try {
System.out.println(map.getString("aaa"));
System.out.println(map.getBoolean("bbb"));
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
container.afterPropertiesSet();
container.start();
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
集成spring配置可以这样写
application.xml
<!-- 配置连接工厂 -->
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="failover:(tcp://localhost:61616)" />
<property name="userName" value="admin"/>
<property name="password" value="admin"/>
</bean>
<!-- 目的地 -->
<bean id="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>queue1</value>
</constructor-arg>
</bean>
<!-- 监听器 -->
<bean id="queueListener" class="com.jsyl.activeMQTest.mq.QueueListener">
</bean>
<!-- 监听器容器 -->
<bean id="queueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="queueDestination" />
<property name="messageListener" ref="queueListener" />
</bean>
测试类
ApplicationContext
看DefaultMessageListenerContainer这个类的源码可以发现这个类实现了BeanNameAware, DisposableBean, SmartLifecycle 和InitializingBean这个四个接口。spring容器在初始化的时候,对于实现了BeanNameAware接口的bean可以知道这个bean自身的name;对于实现了DisposableBean接口的bean,在ApplicationContext 调用close()方法之后会执行destroy()方法;对于实现了SmartLifecycle接口的bean,会在所有bean加载和初始化完成之后调用这个bean的start()方法;对于实现了InitializingBean接口的bean,会在bean初始化的时候执行afterPropertiesSet()方法,afterPropertiesSet()方法比bean里面设置的init-method方法执行要早。
4.使用JmsMessagingTemplate
发送消息
public class MessagingTemplateSender {
public static void main(String[] args) {
JmsMessagingTemplate jmsMessagingTemplate = new JmsMessagingTemplate();
jmsMessagingTemplate.setConnectionFactory(new ActiveMQConnectionFactory("admin", "admin", "tcp://localhost:61616"));
jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), "aaa");
}
}
convertAndSend方法的第二个参数payload(消息的主体)支持String,byte数组,Map<String,?>和可序列化的类
同步接收消息
import org.apache.activemq.ActiveMQConnectionFactory;
import org.springframework.jms.core.JmsMessagingTemplate;
public class MessagingTemplateReceiver {
public static void main(String[] args) throws InterruptedException {
JmsMessagingTemplate jmsMessagingTemplate = new JmsMessagingTemplate();
jmsMessagingTemplate.setConnectionFactory(new ActiveMQConnectionFactory("admin", "admin", "tcp://localhost:61616"));
while(true){
Thread.sleep(1000);
System.out.println(jmsMessagingTemplate.receive("queue1").getPayload());
}
}
}
得到的结果
5.集成Spring Boot
application.yml:
server:
port: 8080
spring:
activemq:
broker-url:tcp://localhost:61616
username:admin
password:admin
pom:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- activemq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
</dependencies>
有了spring-boot-starter-activemq这个依赖之后springboot容器中会有一个JmsMessagingTemplate的对象,通过@Resource/@Autowire直接使用即可
发送消息
import javax.annotation.Resource;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/sendToMq")
public class ActiveMqSenderController {
@Resource
private JmsMessagingTemplate jmsMessagingTemplate;
@RequestMapping("/sendQueue")
public void sendQueue(){
jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), "bbb");
}
@RequestMapping("/test")
public @ResponseBody String test(){
return "test";
}
}
接收消息直接通过@JmsListener即可
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class Consummer {
@JmsListener(destination="queue1",concurrency="")
public void getMessage(String text){
System.out.println("get message:"+text);
}
}
启动springboot项目并访问http://localhost:8080/sendToMq/sendQueue
后台会得到如下:
二、高级特性
1.设置property和messageSelector的使用
在发送消息的时候给消息设置properties
ActiveMQTextMessage msg = new ActiveMQTextMessage();
msg.setText("aaa");
Map<String , Object> map = new HashMap<String, Object>();
map.put("name", "zhangsan");
map.put("age", 10);
msg.setProperties(map);
//也可以这样
//msg.setStringProperty("name", "zhangsan");
//msg.setIntProperty("age", 10);
jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), msg);
ActiveMQTextMessage msg1 = new ActiveMQTextMessage();
msg.setText("bbb");
msg.setStringProperty("name", "lisi");
msg.setIntProperty("age", 20);
jmsMessagingTemplate.convertAndSend(new ActiveMQQueue("queue1"), msg);
接收消息的时候设置消息选择器
@JmsListener(destination="queue1",selector="age > 15 and name='lisi'")
public void getMessage(String text){
System.out.println("get message:"+text);
}
或者不使用springboot注解在创建消费者的时候设置消息选择器
consumer = session.createConsumer(destination,"age > 15 and name='lisi'");
启动后访问接口得到如下
第一条aaa的消息并没有得到
2.组合目的地(Composite Destinations)
有两种方案:
a.客户端
destination = session.createQueue("queue1,queue2");
b.broker
在conf/activemq.xml的broker节点下,添加如下节点
<desinationInterceptors>
<virualDestinationInterceptors>
<virtualDesinations>
<compositeQueue name="queuetest">
<forwardTo>
<queue physicalName="queue1" />
<queue physicalName="queue2" />
<topic physicalName="topic1" />
</forwardTo>
</compositeQueue>
</virtualDestinations>
</virtualDestinationInterceptors>
</destinationInterceptors>
当发送到queuetest这个queue的时候就会发送给queue1,queue2和topic1这三个目的地
3.虚拟主题(Virtual Topic)
对于生产者就是创建一个以VirtualTopic.开头的topic
如:
Topic destination = session.createTopic("VirtualTopic.mytopic");
并设置持久化:
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
对于消费者,可以创建多个Consumer.*.VirtualTopic.mytopic的queue
每一个不同目的地的消费者都可以收到全部消息,同一目的地的消费者共同收到全部消息
示例如下:
生产者:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
public class VirtualSender {
public static void main(String[] args) {
// 连接工厂
ConnectionFactory connectionFactory= new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");;
//JMS 客户端到JMS Provider 的连接
//发送消息的是生产者producer mq的服务器是提供者provider 接受消息的是消费者
Connection connection = null;
// Session: 一个发送或接收消息的线程
//可以设置事务和确认方式
Session session = null;
// Destination :消息的目的地;消息发送给谁.
//可以是一个topic 也可以是一个queue
Destination destination;
// MessageProducer:消息生产者
MessageProducer producer;
// 构造ConnectionFactory实例对象,此处采用ActiveMq的实现jar
connectionFactory = new ActiveMQConnectionFactory(
"admin",
"admin",
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();
// 启动
connection.start();
//createSession 第一个参数transacted 表示是否支持事务
//第二个参数 acknowledgeMode 有如下几种
//1.AUTO_ACKNOWLEDGE 自动确认模式,不需客户端进行确认
//2.CLIENT_ACKNOWLEDGE 客户端进行确认
//客户端获得message之后需要进行message.acknowledge();
//3.DUPS_OK_ACKNOWLEDGE 允许重复消息
session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
// 创建队列名为FirstQueue的目的地
// destination = session.createQueue("queue1,queue2");
destination = session.createTopic("VirtualTopic.TEST");
// 创建将消息发送到该目的地的消息生产者
producer = session.createProducer(destination);
// 持久化模式 NON_PERSISTENT不持久化,PERSISTENT持久化
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
producer.setPriority(4);
for (int i = 0; i < 10; i++) {
TextMessage message = session
.createTextMessage("第"+i+"条消息");
// 发送消息到目的地方
producer.send(message);
}
session.commit();
} catch (Exception e) {
try {
if(null != session){
session.rollback();
}
} catch (JMSException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
}
}
消费者:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class VirtualReceiver {
public static void main(String[] args) {
ConnectionFactory connectionFactory;
Connection connection = null;
Session session;
connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
try {
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
Destination destination1 = session.createQueue("Consumer.A.VirtualTopic.TEST");
MessageConsumer consumer1 = session.createConsumer(destination1);
consumer1.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
try {
System.out.println("Consumer.A 收到消息:" + ((TextMessage)message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Destination destination2 = session.createQueue("Consumer.B.VirtualTopic.TEST");
MessageConsumer consumer2 = session.createConsumer(destination2);
consumer2.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
try {
System.out.println("Consumer.B1 收到消息:" + ((TextMessage)message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
MessageConsumer consumer3 = session.createConsumer(destination2);
consumer3.setMessageListener(new MessageListener() {
public void onMessage(Message message) {
try {
System.out.println("Consumer.B2 收到消息:" + ((TextMessage)message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
while(true){
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection){
connection.close();
}
} catch (Throwable ignore) {
}
}
}
}
先启动消费者在启动生产者得到结果: