ActiveMQ
版本:5.15.11
1 JMS
原始API
操作ActiveMQ
1.1 queue
點對點模式
ActiveMqConfig.java
:
package com.tao.springbootdemo.mq.activemq;
import org.apache.activemq.ActiveMQConnection;
/**
* activemq的配置
*/
public class ActiveMqConfig {
public static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
public static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
public static final String BROKER_URL = "tcp://192.168.48.128:61616";
}
QueueProducer.java
生產者:
package com.tao.springbootdemo.mq.activemq.jms.queue;
import com.tao.springbootdemo.mq.activemq.ActiveMqConfig;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.*;
/**
* queue消息生產者
*/
public class QueueProducer {
private static final Logger LOG = LoggerFactory.getLogger(QueueProducer.class);
private Connection connection;
private Session session;
private MessageProducer producer;
public QueueProducer(String queueName) {
init(queueName);
}
/**
* 初始化
*/
public void init(String queueName) {
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMqConfig.BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(queueName);
producer = session.createProducer(queue);
} catch (JMSException e) {
LOG.error("" + e);
}
}
/**
* 發送消息
*/
public void sendMsg(String message) {
try {
ActiveMQTextMessage msg = new ActiveMQTextMessage();
msg.setText(message);
producer.send(msg);
session.commit();
LOG.info(Thread.currentThread().getName() + " send a message: {}", msg.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
QueueConsumer.java
消費者:
package com.tao.springbootdemo.mq.activemq.jms.queue;
import com.tao.springbootdemo.mq.activemq.ActiveMqConfig;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.*;
/**
* queue消息消費者
*/
public class QueueConsumer {
private static final Logger LOG = LoggerFactory.getLogger(QueueConsumer.class);
private Connection connection;
private Session session;
private MessageConsumer consumer;
public QueueConsumer(String queueName) {
init(queueName);
}
/**
* 初始化
*/
public void init(String queueName) {
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMqConfig.BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(queueName);
consumer = session.createConsumer(queue);
} catch (JMSException e) {
LOG.error("" + e);
}
}
/**
* 接收消息
*/
public void receiveMsg() {
try {
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
LOG.info(Thread.currentThread().getName() + " receive a message : {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
});
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
ActiveMqQueueExample.java
測試類:
package com.tao.springbootdemo.mq.activemq.jms.queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* queue消息測試類
*/
public class ActiveMqQueueExample {
private static final Logger LOG = LoggerFactory.getLogger(ActiveMqQueueExample.class);
public static final String QUEUE_NAME = "activemq-queue-example";
public static void main(String[] args) {
/**
* 循環發送消息
*/
new Thread(() -> {
QueueProducer queueProducer = new QueueProducer(QUEUE_NAME);
while (true) {
queueProducer.sendMsg("發送一條queue消息");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
LOG.error("" + e);
}
}
}).start();
/**
* 監聽消息
*/
new Thread(() -> {
QueueConsumer queueConsumer = new QueueConsumer(QUEUE_NAME);
queueConsumer.receiveMsg();
}).start();
}
}
程序運行結果:
1.2 topic
發佈訂閱模式
TopicPublisher.java
發佈者:
package com.tao.springbootdemo.mq.activemq.jms.topic;
import com.tao.springbootdemo.mq.activemq.ActiveMqConfig;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.*;
/**
* topic消息發佈者
*/
public class TopicPublisher {
private static final Logger LOG = LoggerFactory.getLogger(TopicPublisher.class);
private Connection connection;
private Session session;
private MessageProducer producer;
public TopicPublisher(String topicName) {
init(topicName);
}
/**
* 初始化
*/
public void init(String topicName) {
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMqConfig.BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
producer = session.createProducer(topic);
} catch (JMSException e) {
LOG.error("" + e);
}
}
/**
* 發送消息
*/
public void sendMsg(String message) {
try {
ActiveMQTextMessage msg = new ActiveMQTextMessage();
msg.setText(message);
producer.send(msg);
session.commit();
LOG.info(Thread.currentThread().getName() + " send a message: {}", msg.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
TopicSubscriber.java
訂閱者:
package com.tao.springbootdemo.mq.activemq.jms.topic;
import com.tao.springbootdemo.mq.activemq.ActiveMqConfig;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.*;
/**
* topic消息訂閱者
*
*/
public class TopicSubscriber {
private static final Logger LOG = LoggerFactory.getLogger(TopicSubscriber.class);
private Connection connection;
private Session session;
private MessageConsumer consumer;
public TopicSubscriber(String topicName) {
init(topicName);
}
/**
* 初始化
*/
public void init(String topicName) {
try {
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ActiveMqConfig.BROKER_URL);
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
consumer = session.createConsumer(topic);
} catch (JMSException e) {
LOG.error("" + e);
}
}
/**
* 接收消息
*/
public void receiveMsg() {
try {
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage = (TextMessage) message;
LOG.info(Thread.currentThread().getName() + " receive a message : {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
});
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
ActiveMqTopicExample.java
測試類:
package com.tao.springbootdemo.mq.activemq.jms.topic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* topic消息測試類
*/
public class ActiveMqTopicExample {
private static final Logger LOG = LoggerFactory.getLogger(ActiveMqTopicExample.class);
public static final String TOPIC_NAME = "activemq-topic-test";
public static void main(String[] args) {
/**
* 循環發送消息
*/
new Thread(new Runnable() {
@Override
public void run() {
TopicPublisher topicPublisher = new TopicPublisher(TOPIC_NAME);
while (true) {
topicPublisher.sendMsg("發送一條topic消息");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
LOG.error("" + e);
}
}
}
}).start();
/**
* 接收消息
*/
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
TopicSubscriber topicSubscriber = new TopicSubscriber(TOPIC_NAME);
topicSubscriber.receiveMsg();
}
}
}).start();
}
}
程序運行結果:
2 SpringBoot
通過JmsTemplate
操作ActiveMQ
Spring Boot版本
:2.2.3
引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
官網提示:
如果想要使用連接池,可以添加一個
org.messaginghub:pooled-jms
依賴,並配置JmsPoolConnectionFactory
的屬性:spring.activemq.pool.enabled=true spring.activemq.pool.max-connections=50
配置連接屬性:
# activemq配置
spring.activemq.broker-url: tcp://192.168.48.128:61616
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
# 自定義的queue和topic名字
custom.spring.activemq.queue.name=custom-activemq-queue
custom.spring.activemq.topic.name=custom-activemq-topic
自定義JmsConfig
配置類,配置@EnableJms
,開啓對JMS
的支持,並創建一個queue
和一個topic
交由Spring
管理:
package com.tao.springbootdemo.config;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import javax.jms.Queue;
import javax.jms.Topic;
@Configuration
@EnableJms
public class JmsConfig {
@Value("${custom.spring.activemq.queue.name}")
private String queueName;
@Value("${custom.spring.activemq.topic.name}")
private String topicName;
@Bean
public Queue queue() {
return new ActiveMQQueue(queueName);
}
@Bean
public Topic topic() {
return new ActiveMQTopic(topicName);
}
}
2.1 queue
點對點模式
QueueProducer.java
消息生產者:
package com.tao.springbootdemo.mq.activemq.springjms.queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Queue;
/**
* queue消息生產者
*/
@RestController
@RequestMapping("/queue")
public class QueueProducer {
@Autowired
private JmsTemplate jmsTemplate;
@Autowired
private Queue queue;
/**
* 發送消息
*
* @param msg
* @return
*/
@GetMapping("/send/{msg}")
public String sendQueueMsg(@PathVariable("msg") String msg) {
jmsTemplate.convertAndSend(queue, msg);
return "OK";
}
}
QueueConsumer.java
消息消費者:
package com.tao.springbootdemo.mq.activemq.springjms.queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
/**
* queue消息消費者
*/
@Component
public class QueueConsumer {
private static final Logger LOG = LoggerFactory.getLogger(QueueConsumer.class);
/**
* 監聽並消費消息
*
* @param msg
*/
@JmsListener(destination = "${custom.spring.activemq.queue.name}")
public void receiveQueueMsg(Object msg) {
try {
TextMessage textMessage = (TextMessage) msg;
LOG.info(Thread.currentThread().getName() + " receive a message: {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
測試結果:
通過web
請求觸發消息發送:
消費者接收到消息:
2.2 topic
發佈訂閱模式
要想使用topic
,需要添加一個屬性配置:
# 是否開啓pub/sub模式,默認是false
spring.jms.pub-sub-domain=true
注意:配置
spring.jms.pub-sub-domain
屬性只能一次支持一種,要想同時支持queue
和topic
,需要重寫JmsListenerContainerFactory
。
TopicPublisher.java
消息發佈者:
package com.tao.springbootdemo.mq.activemq.springjms.topic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Topic;
/**
* topic消息發佈者
*/
@RestController
@RequestMapping("/topic")
public class TopicPublisher {
@Autowired
private Topic topic;
@Autowired
private JmsTemplate jmsTemplate;
/**
* 發佈消息
*
* @param msg
* @return
*/
@GetMapping("/publish/{msg}")
public String publishTopicMsg(@PathVariable("msg") String msg) {
jmsTemplate.convertAndSend(topic, msg);
return "OK";
}
}
TopicSubscriber1.java
消息訂閱者1:
package com.tao.springbootdemo.mq.activemq.springjms.topic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
/**
* topic消息訂閱者1
*/
@Component
public class TopicSubscriber1 {
private static final Logger LOG = LoggerFactory.getLogger(TopicSubscriber1.class);
/**
* 監聽消息
*
* @param msg
*/
@JmsListener(destination = "${custom.spring.activemq.topic.name}")
public void receiveMsg(Object msg) {
try {
TextMessage textMessage = (TextMessage) msg;
LOG.info("TopicSubscriber1 receive a message: {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
TopicSubscriber2.java
消息訂閱者2:
package com.tao.springbootdemo.mq.activemq.springjms.topic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
/**
* topic消息訂閱者2
*/
@Component
public class TopicSubscriber2 {
private static final Logger LOG = LoggerFactory.getLogger(TopicSubscriber2.class);
/**
* 監聽消息
*
* @param msg
*/
@JmsListener(destination = "${custom.spring.activemq.topic.name}")
public void receiveMsg(Object msg) {
try {
TextMessage textMessage = (TextMessage) msg;
LOG.info("TopicSubscriber2 receive a message: {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
測試結果:
通過web
請求觸發消息發佈:
兩個消息訂閱者收到消息:
2.3 自定義containerFactory
解決queue
和topic
不能同時使用的問題
首先在JmsConfig
中自定義兩個bean
,queueListenerFactory
用於queue
模式,topicListenerFactory
用於topic
模式:
JmsConfig.java
:
package com.tao.springbootdemo.config;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.jms.Topic;
@Configuration
@EnableJms
public class JmsConfig {
@Value("${custom.spring.activemq.queue.name}")
private String queueName;
@Value("${custom.spring.activemq.topic.name}")
private String topicName;
@Bean
public Queue queue() {
return new ActiveMQQueue(queueName);
}
@Bean
public Topic topic() {
return new ActiveMQTopic(topicName);
}
@Bean
public JmsListenerContainerFactory<?> queueListenerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// 設置queue模式
factory.setPubSubDomain(false);
factory.setConnectionFactory(connectionFactory);
return factory;
}
@Bean
public JmsListenerContainerFactory<?> topicListenerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// 設置topic模式
factory.setPubSubDomain(true);
factory.setConnectionFactory(connectionFactory);
return factory;
}
}
然後在@JmsListener
註解上添加屬性containerFactory
選擇對應的bean
:
QueueConsumer.java
:
package com.tao.springbootdemo.mq.activemq.springjms.queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
/**
* queue消息消費者
*/
@Component
public class QueueConsumer {
private static final Logger LOG = LoggerFactory.getLogger(QueueConsumer.class);
/**
* 監聽並消費消息
*
* @param msg
*/
@JmsListener(destination = "${custom.spring.activemq.queue.name}", containerFactory = "queueListenerFactory")
public void receiveQueueMsg(Object msg) {
try {
TextMessage textMessage = (TextMessage) msg;
LOG.info(Thread.currentThread().getName() + " receive a message: {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
TopicSubscriber1.java
:
package com.tao.springbootdemo.mq.activemq.springjms.topic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.JMSException;
import javax.jms.TextMessage;
/**
* topic消息訂閱者1
*/
@Component
public class TopicSubscriber1 {
private static final Logger LOG = LoggerFactory.getLogger(TopicSubscriber1.class);
/**
* 監聽消息
*
* @param msg
*/
@JmsListener(destination = "${custom.spring.activemq.topic.name}", containerFactory = "topicListenerFactory")
public void receiveMsg(Object msg) {
try {
TextMessage textMessage = (TextMessage) msg;
LOG.info("TopicSubscriber1 receive a message: {}", textMessage.getText());
} catch (JMSException e) {
LOG.error("" + e);
}
}
}
測試程序結果: