一、什么是消息队列?
它是分布式应用间交换信息的重要组件。消息队列可驻留在内存或磁盘上, 队列可以存储消息直到它们被应用程序读走。通过消息队列,应用程序可以在不知道彼此位置的情况下独立处理消息,或者在处理消息前不需要等待接收此消息。所以消息队列可以解决应用解耦、异步消息、流量削锋等问题,是实现高性能、高可用、可伸缩和最终一致性架构中不可以或缺的一环。
简单的来说,消息队列就是独立于客户端与服务端,将消息(请求)以队列的形式存储起来,等待服务端进行读取;
二、消息队列的原理分析
用户1、2、3同时向服务端系统发送请求,三个请求会先被分配到队列中存储起来,服务端会监听队列中的消息,一旦系统空闲,并且监听到队列中有消息,系统就会从队列中取出消息,并进行处理。如此设计,系统可以按照自己的节奏去处理请求,从而减轻服务端的压力,保证业务处理的流畅;即使系统由于某些原因停止运行,由于未处理的请求仍保存在队列中,这些请求也不会丢失。
三、消息队列的架构
消息队列主要分为点对点(Queue)模式和订阅(Topic)模式两种
主要角色有生产者、消息、队列、消费者
如图所示点对点模式: 生产者Producer将生产出来的消息塞入到队列Queue中,消费者Consumer从队列中取出消息并消费,被消费完的消息不会存在在队列中,一条消息只会被一个消费者消费一次;
四、实战操作
1、先启动ActiveMQ服务
2、在pom.xml添加相应的包
<!-- 整合消息队列ActiveMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<!-- 如果配置线程池则加入 -->
<dependency>
<groupId>org.messaginghub</groupId>
<artifactId>pooled-jms</artifactId>
</dependency>
3.配置文件application.properties
#整合jms测试,安装在别的机器,防火墙和端口号记得开放
spring.activemq.broker-url=tcp://127.0.0.1:61616
#集群配置
#spring.activemq.broker-url=failover:(tcp://localhost:61616,tcp://localhost:61617)
spring.activemq.user=admin
spring.activemq.password=admin
#下列配置要增加依赖
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=100
4、springboot启动类中启用JMS
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.annotation.EnableJms;
import javax.jms.Queue;
@SpringBootApplication
@EnableJms //启用JMS
public class MqDemoApplication {
@Bean //交给spring来管理,注入哦!
public Queue queue(){
return new ActiveMQQueue("common.queue");
}
public static void main(String[] args) {
SpringApplication.run(MqDemoApplication.class, args);
}
}
5、生产消息接口
/**
* 消息生产
*/
public interface ProducerService {
//指定消息队列,还有消息
public void sendMessage(Destination destination, final String msg);
//使用默认消息队列, 发送消息
public void sendMessage(final String msg);
}
6、实现生产消息接口
/**
* 实现消息信息类
*/
@Service
public class ProducerServiceImpl implements ProducerService {
// 用来发送消息到broker的对象
@Autowired
private JmsMessagingTemplate jmsTemplate;
//注入指定消息队列 (在启动类中有注入哦!)
@Autowired
private Queue queue;
@Override
public void sendMessage(Destination destination, String msg) {
// System.out.println("jmsTemplate="+jmsTemplate+"\t"+destination+"\t"+msg);
jmsTemplate.convertAndSend(destination, msg);
System.out.println("发送信息指定目标:"+msg);
}
@Override
public void sendMessage(String msg) {
jmsTemplate.convertAndSend(this.queue,msg); //指定消息队列哦!!!
System.out.println("发送信息默认目标:"+msg);
}
}
7、控制类访问
@RestController
@RequestMapping("/activemq/my")
public class OrderController {
@Autowired //注入消息生产者
private ProducerService service;
/**
* 微信支付回调接口
*/
@GetMapping("order")
public Object order(String msg){
//目的地:生成消息队列地址
Destination destination =new ActiveMQQueue("order.queue");
//调用方法
service.sendMessage(destination,msg);
return JsonData.buildSuccess();
}
@GetMapping("comm")
public Object comm(String msg) {
//调用方法
service.sendMessage(msg);
return JsonData.buildSuccess();
}
}
8、启动运行
可以发多个信息哦! http://localhost:8080/activemq/my/order?msg=116
再查看ActiveMQ服务
3个请求入队后:此时队列中有3条入队(未被处理)的消息;
9、消费者消费类
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
/**
*消费者
*/
@Component
public class OrderConsumer {
//实时监听器监听order.queue这个消息队列
@JmsListener(destination = "order.queue")
public void receiveQueue(String text){
System.out.println("OrderConsumer收到的消息为:"+text);
}
}
10、重新运行 监听到刚才发的信息了
11、重新发信息,实时监听。
12、消费者使用默认队列(common.queue)来消费
/**
*消费者
*/
@Component
public class CommConsumer {
//实时监听器监听order.queue这个消息队列
@JmsListener(destination = "common.queue")
public void receiveQueue(String text){
System.out.println("CommConsumer收到的消息为:"+text);
}
}
请求被服务端取走后:队列中再无其他消息,两条消息均已出列;
总之: 消息队列并不能提高系统的运行速度(如果想提高速度,还是需要用到多线程等方式),消息队列作为中间件的作用是降低应用间的耦合,在高并发、高流量的情况下保证服务端的稳定,保证业务流程的顺畅和数据的完整(请求不丢失)。