摘要:
MQ全称为Message Queue,
消息队列
(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如
远程过程调用
的技术。
RabbitMQ
是一个在
AMQP
基础上完成的,可复用的企业消息系统。以下实例请先安装RabbitMQ。
一、几个概念
Exchange:交换机,决定了消息路由规则;
Queue:消息队列;
Channel:进行消息读写的通道;
Bind:绑定了Queue和Exchange,意即为符合什么样路由规则的消息,将会放置入哪一个
消息队列
;
二、消息持久
1) 将交换机置为可持久;
2) 将通道置为可持久
3) 消息发送时设置可持久。
当我们“生产”了一条可持久化的消息,尝试中断MQ服务,启动消费者获取消息,消息依然能够恢复。相反,则抛出异常。
以下为2幅原理图:
- 左侧 P 代表 生产者,也就是往 RabbitMQ 发消息的程序。
- 中间即是 RabbitMQ,其中包括了 交换机 和 队列。
- 右侧 C 代表 消费者,也就是往 RabbitMQ 拿消息的程序。
三、各种模式消息队列
3.1、简单队列
@Configuration
public class RabbitConfig {
//简单队列
private static final String QUEUE_SIMPLE_NAME = "test_simple_queue";
@Bean
public Queue Queue() {
return new Queue(QUEUE_SIMPLE_NAME, false, false, false, null);
}
}
编写测试方法
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMQApplicationTests {
@Autowired
private AmqpTemplate amqpTemplate;
@Test
public void testSimpleQueue() {
String message = "Hello RabbitMQ !";
amqpTemplate.convertAndSend("test_simple_queue", message);
System.out.println("[x] send " + message + " ok");
}
}
3.2、工作队列
公平分发模式在Spring-amqp中是默认的,这种情况也是日常工作中使用最为正常的,轮询模式用的较少,区别在于prefetch默认是1,如果设置为0就是轮询模式。
@Configuration
public class RabbitConfig {
//工作队列
private static final String QUEUE_WORK_NAME = "test_workfair_queue";
@Bean
public Queue workQueue() {
return new Queue(QUEUE_WORK_NAME, false, false, false, null);
}
}
编写测试方法
//测试工作队列
@Test
public void testWorkFairQueue(){
for (int i = 0; i < 20; i++) {
String message = "Hello RabbitMQ " + i;
// 发送消息
amqpTemplate.convertAndSend("test_workfair_queue", message);
System.out.println(" [x] Sent '" + message + "'");
try {
Thread.sleep(i*100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.3、轮询分发模式
spring:
rabbitmq:
host: 192.168.239.128
port: 5672
#username: test
#password: 123456
#virtual-host: /vhost_test
#publisher-confirms: true
listener:
simple:
prefetch: 0
3.4、订阅模式
package com.pdcourse.rabbitmq;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author:chenyiwu
* @Describtion:
* @Create Time:2018/6/14
*/
@Configuration
public class RabbitConfig {
//发布订阅模式
private static final String EXCHANGE_FANNOUT_NAME = "test_exchange_fanout";
private static final String QUEUE_PS_SMS_NAME = "test_queue_fanout_sms";
private static final String QUEUE_PS_EMAIL_NAME = "test_queue_fanout_email";
@Bean("fanoutExchange")
public FanoutExchange fanoutExchange() {
return new FanoutExchange(EXCHANGE_FANNOUT_NAME);
}
@Bean
public Queue fanoutSmsQueue() {
return new Queue(QUEUE_PS_SMS_NAME, false, false, false, null);
}
@Bean
public Queue fanoutEmailQueue() {
return new Queue(QUEUE_PS_EMAIL_NAME, false, false, false, null);
}
@Bean
public Binding smsQueueExchangeBinding(FanoutExchange fanoutExchange, Queue fanoutSmsQueue) {
return BindingBuilder.bind(fanoutSmsQueue).to(fanoutExchange);
}
@Bean
public Binding emailQueueExchangeBinding(FanoutExchange fanoutExchange, Queue fanoutEmailQueue) {
return BindingBuilder.bind(fanoutEmailQueue).to(fanoutExchange);
}
}
package com.pdcourse.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Author:chenyiwu
* @Describtion: 邮件订阅者
* @Create Time:2018/6/15
*/
@RabbitListener(queues = "test_queue_fanout_email")
@Component
public class EmailRecv {
@RabbitHandler
public void process(String message) {
System.out.println("[email] rev : " + message);
}
}
package com.pdcourse.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Author: chenyiwu
* @Describtion: 短信订阅者
* @Create Time:2018/6/15
*/
@RabbitListener(queues = "test_queue_fanout_sms")
@Component
public class SmsRecv {
@RabbitHandler
public void process(String message) {
System.out.println("[sms] rev : " + message);
}
}
测试:
//订阅模式
@Test
public void testFanoutQueue() {
String message = "Hello, fanout message ";
// 发送消息
amqpTemplate.convertAndSend("test_exchange_fanout", "", message);
System.out.println(" [x] Sent '" + message + "'");
}