springboot 整合 activemq
- 这个demo纯粹是一个小demo 因为为了学习dubbo,在这个demo是实现了发布订阅和点对点两种模式
别的不多说,直接上代码: 结尾我会把代码贴上去
首先引入依赖
<!-- 整合消息队列ActiveMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- 配置线程池 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
SpringBoot+ActiveMQ实战之点对点模式(p2p)
activemq:
broker-url: tcp://127.0.0.1:61616 #地址
user: admin
password: admin
pool:
enabled: true
max-connections: 100 #线程池
启动类添加@EnableJms注解,开启支持jms
- 在springboot启动类添加一个 queue对象,并交给spring进行管理
@Bean
public Queue queue() {
return new ActiveMQQueue("message.queue");
}
- 定义消息的生产者和消费者
import com.itcorey.service.ProducerService;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @Classname MessageController
* @Description 定义消息的生产者和消费者
* @Date 2020/5/19 14:44
* @Created by corey
*/
@RestController
@RequestMapping("/api/message")
public class MessageController {
@Resource
private ProducerService producerService;
@GetMapping("/send")
public String sendMsg(String message) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0;i<=10;i++){
// 目的地
ActiveMQQueue desination = new ActiveMQQueue("message.queue");
// 发送消息
producerService.sendMessage(message, desination);
}
}
}).start();
return "success!!";
}
}
- ProducerService.java
package com.itcorey.service;
import javax.jms.Destination;
/**
* @Classname ProducerService
* @Description 消息生产者
* @Date 2020/5/19 14:47
* @Created by corey
*/
public interface ProducerService {
void sendMessage(final String msg);
void sendMessage(final String msg, Destination destination);
void publish(final String msg);
}
ProducerServiceImpl.java
@Service
public class ProducerServiceImpl implements ProducerService {
@Autowired
private Queue queue;// 默认消息队列
@Autowired
private JmsMessagingTemplate JmsTemplate; // 用来发送消息到broker的对象
//发送消息
@Override
public void sendMessage(String msg) {
JmsTemplate.convertAndSend(this.queue, msg);
}
//发送消息
@Override
public void sendMessage(String msg, Destination destination) {
JmsTemplate.convertAndSend(destination, msg);
}
}
MessageConsumer.java:
@Component
public class MessageConsumer {
@JmsListener(destination = "message.queue")
public void receiveMessage(String txt) {
System.out.println("MessageConsumer接收到的信息:" + txt);
}
}
模拟请求
请求地址:http://localhost:8080/api/message/send?message=hello
结果
二、SpringBoot+ActiveMQ实战之发布订阅模式(pub/sub)
需要加入配置文件,支持发布订阅模型,默认只支持点对点
#default point to point
spring.jms.pub-sub-domain=true
添加topic对象
@EnableJms
@SpringBootApplication
public class ActivemqWebApplication {
@Bean
public Topic topic() {
return new ActiveMQTopic("news.topic");
}
@Bean
ConnectionFactory connectionFactory() {
return new ActiveMQConnectionFactory();
}
@Bean
JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
jmsTemplate.setPriority(999);
return jmsTemplate;
}
@Bean(value = "jmsMessagingTemplate")
JmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {
JmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jmsTemplate);
return messagingTemplate;
}
public static void main(String[] args) {
SpringApplication.run(ActivemqWebApplication.class, args);
}
}
定义消息的发布者和订阅者
NewsController.java
package com.itcorey.controller;
import com.itcorey.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Classname NewsController
* @Description TODO
* @Date 2020/5/19 15:47
* @Created by corey
*/
@RequestMapping("/api/news")
@RestController
public class NewsController {
@Autowired
private ProducerService producerService;
@GetMapping("/publish")
public String publish(String news) {
// 发布信息
producerService.publish(news);
return "success!!!";
}
}
ProducerService
ProducerServiceImpl实现
@Service
public class ProducerServiceImpl implements ProducerService {
private Topic topic; // 默认主题
@Autowired
private JmsMessagingTemplate JmsTemplate; // 用来发送消息到broker的对象
/**
* 功能描述:发布消息
*/
@Override
public void publish(String msg) {
JmsTemplate.convertAndSend(this.topic, msg);
}
}
NewsSub.java
@Component
public class NewsSub {
@JmsListener(destination = "news.topic")
public void receive1(String text) {
System.out.println("news.topic 消费者:receive1=" + text);
}
@JmsListener(destination = "news.topic")
public void receive2(String text) {
System.out.println("news.topic 消费者:receive2=" + text);
}
@JmsListener(destination = "news.topic")
public void receive3(String text) {
System.out.println("news.topic 消费者:receive3=" + text);
}
}
模拟测试
请求地址:http://localhost:8080/api/news/publish?news=topic
注意,如果相同时兼容两种情况,P2P和pub/sub两种.
@JmsListener如果不指定独立的containerFactory的话是只能消费queue消息,需要修改订阅者container:containerFactory=“jmsListenerContainerTopic”
@Component
public class NewsSub {
@JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
public void receive1(String text) {
System.out.println("news.topic 消费者:receive1=" + text);
}
@JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
public void receive2(String text) {
System.out.println("news.topic 消费者:receive2=" + text);
}
@JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
public void receive3(String text) {
System.out.println("news.topic 消费者:receive3=" + text);
}
}
需要在启动类给topic定义独立的JmsListenerContainer
@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ConnectionFactory activeMQConnectionFactory) {
DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
bean.setPubSubDomain(true);
bean.setConnectionFactory(activeMQConnectionFactory);
return bean;
}
在配置文件里面,注释掉 #spring.jms.pub-sub-domain=true
写在最后:
1.什么是JMS
JMS是java消息服务(java Message service) 应用接口,是一个java平台中关于面向消息中间件(MOM)的API,用于两个程序之间,或分布式系统中发送消息进行异步通信.Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持(百度百科给出的概述)。我们可以简单的理解:两个应用程序之间需要进行通信,我们使用一个JMS服务,进行中间的转发,通过JMS 的使用,我们可以解除两个程序之间的耦合。
2. JMS的优势
- Asynchronous(异步)
JMS 原本就是一个异步的消息服务,客户端获取消息的时候,不需要主动发送请求,消息会自动发送给可用的客户端。
2. Reliable(可靠)
JMS保证消息只会递送一次。大家都遇到过重复创建消息问题,而JMS能帮你避免该问题。
3 JMS的消息模式
点对点通信模型(Point-to-Point)在点对点通信模式中,应用程序由消息队列,发送方,接收方组成。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。
特点:
- 每个消息只要一个消费者
- 发送者接受者在时间上没有时间约束,也就是说发送者在发送完消息之后,不管接收者有没有接受消息,都不会影响发送方发送消息到消息队列中。
- 发送方不管是否在发送消息,接收方都可以从消息队列中取到消息,(The receiver can fetch message whether it is running or not when the sender sends the message)。
- 接收方在接收完消息之后,需要向消息队列应答成功。
- 发布/订阅通信模型(Publish/Subscribe Messaging Domain)
在发布/订阅消息模型中,发布者发布一个消息,该消息通过topic传递给所有的客户端,该模式下,发布者与订阅者都是匿名的,即发布者与订阅者都不知道对方是谁。并且可以动态的发布与订阅Topic。Topic主要用于保存和传递消息,且会一直保存消息直到消息被传递给客户端。
特点
- 一个消息可以传递个多个订阅者(即:一个消息可以有多个接受方)。
- 发布者与订阅者具有时间约束,针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。
- 为了缓和这样严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。
JMS的编程模型
- ConnectionFactory:连接工厂,JMS用它创建连接
- Connnection:连接对象,JMS Client到JMS Provider的连接
- Destination:消息目的地,由Session创建
- Session:会话,由Connection创建,实质上就是发送、接受消息的一个线程,因此生产者、消费者都是Session创建的
- Provider/MessageProvider:消息生产者
- Consumer/MessageConsumer:消息消费者
- Message Listeners:消息监听者
源码地址:https://github.com/coreyxuy/springboot-email.git