【RabbitMQ学习之二】RabbitMQ四种交换机模式应用
环境
win7
rabbitmq-server-3.7.17
Erlang 22.1
一、概念
1、队列
队列用于临时存储消息和转发消息。
队列类型有两种,即时队列和延时队列。
即时队列:队列中的消息会被立即消费;
延时队列:队列中的消息会在指定的时间延时之后被消费。
2、交换机
交换机的功能主要是接收消息并且转发到绑定的队列,交换机不存储消息,在启用ack模式后,交换机找不到队列会返回错误。
交换机有四种类型:Direct, topic, Headers and Fanout。
Direct[精确匹配类型]:Direct是RabbitMQ默认的交换机模式,先匹配, 再投送。即创建消息队列的时候,指定一个BindingKey.当发送者发送消息的时候,指定对应的Key.当Key和消息队列的BindingKey一致的时候,消息将会被发送到该消息队列中.
Topic[模式匹配]:按通配符匹配规则转发消息(最灵活),队列和交换机的绑定主要是依据一种模式(通配符+字符串),而当发送消息的时候,只有指定的Key和该模式相匹配的时候,消息才会被发送到该消息队列中.
Headers[键值对匹配]:设置header attribute参数类型的交换机。
消息队列和交换机绑定的时候会指定一组键值对规则,而发送消息的时候也会指定一组键值对规则,当两组键值对规则相匹配的时候,消息会被发送到匹配的消息队列中.
Fanout[转发消息最快]:
路由广播的形式,简单的将队列绑定到交换机上将会把消息发给绑定它的全部队列,即便设置了key,也会被忽略.
3、使用spring boot和rabbitmq整合 搭建演示工程
二、Direct Exchange-Work模式
配置类:
package com.wjy.direct; import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; //@Configuration这个注解是必须的,保证在基本类实例化之前该类已经被实例化
@Configuration
public class RabbitConfig { /**
* @Desc: 配置一个消息队列(routingKey=q_hello)
*/
@Bean
public Queue queue() {
return new Queue("q_hello");
} /**
* @Desc: 配置一个消息队列(routingKey=notify.refund)
*/
@Bean
public Queue refundNotifyQueue() {
return new Queue("notify.refund");
} /**
* @Desc: 配置一个消息队列(routingKey=query.order) 测试RPC
*/
@Bean
public Queue queryOrderQueue() {
return new Queue("query.order");
}
}
生产者:
package com.wjy.direct; import com.wjy.mojo.Order;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.text.SimpleDateFormat;
import java.util.Date; /**
* @Desc: 生产者
*/
@Component
public class MqSender {
@Autowired
private AmqpTemplate rabbitTemplate; /**
* @Desc: 将消息发送至默认的交换机且routingKey为q_hello
*/
public void send() {
//24小时制
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
String context = "hello " + date;
System.err.println("Sender : " + context);
//简单对列的情况下routingKey即为Q名
this.rabbitTemplate.convertAndSend("q_hello", context);
} /**
* @Desc: 将消息发送至默认的交换机且routingKey为q_hello
*/
public void send(String i) {
//24小时制
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
String context = "hello " + i + " " + date;
System.err.println("Sender : " + context);
//简单对列的情况下routingKey即为Q名
this.rabbitTemplate.convertAndSend("q_hello", context);
} /**
* @Desc: 将发送对象
*/
public void sender(Order order){
System.err.println("notify.refund send message: "+order);
rabbitTemplate.convertAndSend("notify.refund", order);
} /**
* @Desc: 测试RPC
*/
public void sender(String orderId){
System.err.println("query.order send message: "+orderId);
Order order = (Order) rabbitTemplate.convertSendAndReceive("query.order", orderId);
System.err.println("query.order return message: "+order);
}
}
消费者:
package com.wjy.direct; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; /**
* @Desc: 消费者
*/
@Component
@RabbitListener(queues = "q_hello")
public class Receiver { /**
* @Desc: 监听routingKey为nq_hello的队列消息
*/
@RabbitHandler
public void process(String hello) {
System.err.println("Receiver1 : " + hello);
}
}
package com.wjy.direct; import com.wjy.mojo.Order;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
@RabbitListener(queues = "notify.refund")
public class RefundNotifyReceive {
@RabbitHandler
public void receive(Order order) {
System.err.println("notify.refund receive message: "+order);
}
}
package com.wjy.direct; import com.wjy.mojo.Order;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; import java.math.BigDecimal;
import java.util.Date; @Component
@RabbitListener(queues = "query.order")
public class QueryOrderReceive {
@RabbitHandler
public Order receive(String orderId) {
System.err.println("notify.refund receive message: "+orderId); Order order = new Order();
order.setId(100001);
order.setOrderId(orderId);
order.setAmount(new BigDecimal("2999.99"));
order.setCreateTime(new Date());
return order;
}
}
测试类:
package com.wjy.direct; import com.wjy.mojo.Order;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import java.math.BigDecimal;
import java.util.Date; /**
* @Desc: 测试类
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class DirectExchangeTest {
@Autowired
private MqSender mqSender; @Test
public void hello() throws Exception {
mqSender.send();
} /**
* @Desc: 一对多
* 应用场景:系统通常会做集群、分布式或灾备部署
*/
@Test
public void oneToMany() throws Exception {
for (int i=0;i<100;i++){
mqSender.send(i+"");
Thread.sleep(200);
}
} /**
* @Desc: 多对一 请求参数为偶数
* 应用场景:系统通常会做集群、分布式或灾备部署
*/
@Test
public void test_sender_many2one_1() throws Exception {
for (int i = 0; i < 20; i+=2) {
mqSender.send("支付订单号:"+i);
Thread.sleep(1000);
}
} /**
* @Desc: 多对一 请求参数为奇数
* 应用场景:系统通常会做集群、分布式或灾备部署
*/
@Test
public void test_sender_many2one_2() throws Exception {
for (int i = 1; i < 20; i+=2) {
mqSender.send("支付订单号:"+i);
Thread.sleep(1000);
}
} /**
* @Desc: 测试发送对象
*/
@Test
public void test_sender() {
Order order = new Order();
order.setId(100001);
order.setOrderId(String.valueOf(System.currentTimeMillis()));
order.setAmount(new BigDecimal("1999.99"));
order.setCreateTime(new Date());
mqSender.sender(order);
} /**
* @Desc: 测试RPC
* RabbitMQ支持RPC远程调用,同步返回结果。
* 虽然RabbitMQ支持RPC接口调用,但不推荐使用
* 原因:
* 1)RPC默认为单线程阻塞模型,效率极低。
* 2)需要手动实现多线程消费。
*/
@Test
public void test_rpc() {
mqSender.sender("900000001");
}
}
三、Topic Exchange-主题模式
符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词.
配置类:
package com.wjy.topic; import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class TopicRabbitConfig { final static String message = "api.core";
final static String messages = "api.payment"; /**
* 配置一个routingKey为api.core的消息队列
*/
@Bean
public Queue coreQueue() {
return new Queue(TopicRabbitConfig.message);
} /**
* @Desc: 配置一个routingKey为api.payment的消息队列
*/
@Bean
public Queue paymentQueue() {
return new Queue(TopicRabbitConfig.messages);
} /**
* @Desc: coreExchange交换机
*/
@Bean
public TopicExchange coreExchange() {
return new TopicExchange("coreExchange");
} /**
* @Desc: paymentExchange交换机
*/
@Bean
public TopicExchange paymentExchange() {
return new TopicExchange("paymentExchange");
} /**
* 配置一个routingKey为api.core的消息队列并绑定在coreExchange交换机上(交换机的匹配规则为api.core.*)
*/
@Bean
public Binding bindingCoreExchange(Queue coreQueue, TopicExchange coreExchange) {
return BindingBuilder.bind(coreQueue).to(coreExchange).with("api.core.*");
} /**
* @Desc: 配置一个routingKey为api.payment的消息队列并绑定在paymentExchange交换机上(交换机的匹配规则为api.payment.#)
*/
@Bean
public Binding bindingPaymentExchange(Queue paymentQueue, TopicExchange paymentExchange) {
return BindingBuilder.bind(paymentQueue).to(paymentExchange).with("api.payment.#");
}
}
生产者:
package com.wjy.topic; import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class ApiCoreSender {
@Autowired
private AmqpTemplate rabbitTemplate; /**
* @Desc: 发送消息至coreExchange交换机且routingKey为api.core.user
*/
public void user(String msg){
System.err.println("api.core.user send message: "+msg);
rabbitTemplate.convertAndSend("coreExchange", "api.core.user", msg);
} /**
* @Desc: 发送消息至coreExchange交换机且routingKey为api.core.user.query
*/
public void userQuery(String msg){
System.err.println("api.core.user.query send message: "+msg);
rabbitTemplate.convertAndSend("coreExchange", "api.core.user.query", msg);
}
}
package com.wjy.topic; import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class ApiPaymentSender {
@Autowired
private AmqpTemplate rabbitTemplate; /**
* @Desc: 添加一个order()方法,发送消息至paymentExchange交换机且routingKey为api.payment.order
*/
public void order(String msg){
System.err.println("api.payment.order send message: "+msg);
rabbitTemplate.convertAndSend("paymentExchange", "api.payment.order", msg);
} /**
* @Desc: 添加一个orderQuery()方法,发送消息至paymentExchange交换机且routingKey为api.payment.order.query
*/
public void orderQuery(String msg){
System.err.println("api.payment.order.query send message: "+msg);
rabbitTemplate.convertAndSend("paymentExchange", "api.payment.order.query", msg);
} /**
* @Desc: 添加一个orderDetailQuery()方法,发送消息至paymentExchange交换机且routingKey为api.payment.order.detail.query
*/
public void orderDetailQuery(String msg){
System.err.println("api.payment.order.detail.query send message: "+msg);
rabbitTemplate.convertAndSend("paymentExchange", "api.payment.order.detail.query", msg);
}
}
消费者:
package com.wjy.topic; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
public class ApiCoreReceive {
@RabbitHandler
@RabbitListener(queues = "api.core")
public void handle(String msg) {
System.err.println("api.core receive message: "+msg);
}
}
package com.wjy.topic; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
public class ApiPaymentReceive {
@RabbitHandler
@RabbitListener(queues = "api.payment")
public void handle(String msg) {
System.err.println("api.payment.order receive message: "+msg);
}
}
测试类:
package com.wjy.topic; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
public class ApiCoreSenderTests {
@Autowired
private ApiCoreSender sender; @Test
public void test_user() {
sender.user("用户管理!");
} @Test
public void test_userQuery() {
sender.userQuery("查询用户信息!");
}
}
package com.wjy.topic; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
public class ApiPaymentSenderTests {
@Autowired
private ApiPaymentSender sender; @Test
public void test_order() {
sender.order("订单管理!");
} @Test
public void test_orderQuery() {
sender.orderQuery("查询订单信息!");
} @Test
public void test_orderDetailQuery() {
sender.orderDetailQuery("查询订单详情信息!");
}
}
四、Fanout Exchange-订阅模式
配置类:
package com.wjy.fanout; 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; @Configuration
public class FanoutConfig { /**
* @Desc: 配置一个routingKey为api.report.payment的消息队列
*/
@Bean
public Queue reportPaymentQueue() {
return new Queue("api.report.payment");
} /**
* @Desc: 配置一个routingKey为api.report.refund的消息队列
*/
@Bean
public Queue reportRefundQueue() {
return new Queue("api.report.refund");
} /**
* @Desc: 配置一个reportExchange交换机
*/
@Bean
public FanoutExchange reportExchange() {
return new FanoutExchange("reportExchange");
} /**
* @Desc: 配置routingKey为api.report.payment的消息队列并绑定在reportExchange交换机上
*/
@Bean
public Binding bindingReportPaymentExchange(Queue reportPaymentQueue, FanoutExchange reportExchange) {
return BindingBuilder.bind(reportPaymentQueue).to(reportExchange);
} /**
* @Desc: 配置routingKey为api.report.refund的消息队列并绑定在reportExchange交换机上
*/
@Bean
public Binding bindingReportRefundExchange(Queue reportRefundQueue, FanoutExchange reportExchange) {
return BindingBuilder.bind(reportRefundQueue).to(reportExchange);
}
}
生产者:
package com.wjy.fanout; import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class ApiReportSender {
@Autowired
private AmqpTemplate rabbitTemplate; public void generateReports(String msg){
System.err.println("api.generate.reports send message: "+msg);
rabbitTemplate.convertAndSend("reportExchange", "api.generate.reports", msg);
}
}
消费者:
package com.wjy.fanout; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
public class ApiReportReceive {
@RabbitHandler
@RabbitListener(queues = "api.report.payment")
public void payment(String msg) {
System.err.println("api.report.payment receive message: "+msg);
} @RabbitHandler
@RabbitListener(queues = "api.report.refund")
public void refund(String msg) {
System.err.println("api.report.refund receive message: "+msg);
}
}
测试类:
package com.wjy.fanout; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
public class ApiReportSenderTests {
@Autowired
private ApiReportSender sender; @Test
public void test_generateReports() {
sender.generateReports("开始生成报表!");
}
}
五、Headers Exchange
配置类:
package com.wjy.headers; import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.HashMap;
import java.util.Map; @Configuration
public class HeadersConfig {
/**
* @Desc: 配置一个routingKey为credit.bank的消息队列
*/
@Bean
public Queue creditBankQueue() {
return new Queue("credit.bank");
} /**
* @Desc: 配置一个routingKey为credit.finance的消息队列
*/
@Bean
public Queue creditFinanceQueue() {
return new Queue("credit.finance");
} /**
* @Desc: 配置一个creditBankExchange交换机
*/
@Bean
public HeadersExchange creditBankExchange() {
return new HeadersExchange("creditBankExchange");
} /**
* @Desc: 配置一个creditFinanceExchange交换机
*/
@Bean
public HeadersExchange creditFinanceExchange() {
return new HeadersExchange("creditFinanceExchange");
} /**
* @Desc: 配置一个routingKey为credit.bank的消息队列并绑定在creditBankExchange交换机上
*/
@Bean
public Binding bindingCreditAExchange(Queue creditBankQueue, HeadersExchange creditBankExchange) {
Map<String,Object> headerValues = new HashMap<>();
headerValues.put("type", "cash");
headerValues.put("aging", "fast");
//whereall 完全匹配
return BindingBuilder.bind(creditBankQueue).to(creditBankExchange).whereAll(headerValues).match();
} /**
* @Desc: 配置一个routingKey为credit.finance的消息队列并绑定在creditFinanceExchange交换机上
*/
@Bean
public Binding bindingCreditBExchange(Queue creditFinanceQueue, HeadersExchange creditFinanceExchange) {
Map<String,Object> headerValues = new HashMap<>();
headerValues.put("type", "cash");
headerValues.put("aging", "fast");
//whereany 其中一项匹配即可
return BindingBuilder.bind(creditFinanceQueue).to(creditFinanceExchange).whereAny(headerValues).match();
}
}
生产者:
package com.wjy.headers; import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.amqp.support.converter.SimpleMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.util.Map; @Component
public class ApiCreditSender {
@Autowired
private AmqpTemplate rabbitTemplate; public void creditBank(Map<String, Object> head, String msg){
System.err.println("credit.bank send message: "+msg);
rabbitTemplate.convertAndSend("creditBankExchange", "credit.bank", getMessage(head, msg));
} public void creditFinance(Map<String, Object> head, String msg){
System.err.println("credit.finance send message: "+msg);
rabbitTemplate.convertAndSend("creditFinanceExchange", "credit.finance", getMessage(head, msg));
} private Message getMessage(Map<String, Object> head, Object msg){
MessageProperties messageProperties = new MessageProperties();
for (Map.Entry<String, Object> entry : head.entrySet()) {
messageProperties.setHeader(entry.getKey(), entry.getValue());
}
MessageConverter messageConverter = new SimpleMessageConverter();
return messageConverter.toMessage(msg, messageProperties);
}
}
消费者:
package com.wjy.headers; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
public class ApiCreditReceive {
@RabbitHandler
@RabbitListener(queues = "credit.bank")
public void creditBank(String msg) {
System.err.println("credit.bank receive message: "+msg);
} @RabbitHandler
@RabbitListener(queues = "credit.finance")
public void creditFinance(String msg) {
System.err.println("credit.finance receive message: "+msg);
}
}
测试类:
package com.wjy.headers; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap;
import java.util.Map; @RunWith(SpringRunner.class)
@SpringBootTest
public class ApiCreditSenderTests {
@Autowired
private ApiCreditSender sender; @Test
public void test_creditBank_type() {
Map<String,Object> head = new HashMap<>();
head.put("type", "cash");
sender.creditBank(head, "银行授信(部分匹配)");
} @Test
public void test_creditBank_all() {
Map<String,Object> head = new HashMap<>();
head.put("type", "cash");
head.put("aging", "fast");
sender.creditBank(head, "银行授信(全部匹配)");
} @Test
public void test_creditFinance_type() {
Map<String,Object> head = new HashMap<>();
head.put("type", "cash");
sender.creditFinance(head, "金融公司授信(部分匹配)");
} @Test
public void test_creditFinance_all() {
Map<String,Object> head = new HashMap<>();
head.put("type", "cash");
head.put("aging", "fast");
sender.creditFinance(head, "金融公司授信(全部匹配)");
}
}
六、延时队列
配置类:
package com.wjy.delaymq; import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.util.HashMap;
import java.util.Map; @Configuration
public class QueueConfiguration { /**
* @Desc:消息队列app.queue.hello
*/
@Bean
public Queue helloQueue() {
Queue queue = new Queue("app.queue.hello", true, false, false);
return queue;
} /**
* 默认即时消息交换机
*/
@Bean("defaultDirectExchange")
public DirectExchange defaultDirectExchange() {
return new DirectExchange("default.direct.exchange", true, false);
} /**
* @Desc:消息队列app.queue.hello绑定到默认队列上
* 交换机匹配规则:app.queue.hello
*/
@Bean
public Binding helloBinding() {
return BindingBuilder.bind(helloQueue()).to(defaultDirectExchange()).with("app.queue.hello");
} /**
* 配置延迟消息死信队列
*/
@Bean
public Queue defaultDeadLetterQueue() {
Map<String, Object> arguments = new HashMap<>();
//设置交换机路由
arguments.put("x-dead-letter-exchange", "default.direct.exchange");
//设置转发队列名称
arguments.put("x-dead-letter-routing-key", "default.repeat.trade.queue");
Queue queue = new Queue("default.dead.letter.queue", true, false, false, arguments);
return queue;
} /**
* @Desc:将延迟消息队列绑定到延迟交换机上
* 交换机匹配规则:default.dead.letter.queue
*/
@Bean
public Binding defaultDeadLetterBinding() {
Binding bind = BindingBuilder.bind(defaultDeadLetterQueue()).to(defaultDirectExchange()).with("default.dead.letter.queue");
return bind;
} /**
* 配置转发消息队列default.repeat.trade.queue
* @return
*/
@Bean
public Queue defaultRepeatTradeQueue() {
Queue queue = new Queue("default.repeat.trade.queue", true, false, false);
return queue;
} /**
* 转发队列和默认交换机的绑定;
* 交换机匹配规则:default.repeat.trade.queue
*/
@Bean
public Binding defaultRepeatTradeBinding() {
return BindingBuilder
.bind(defaultRepeatTradeQueue())
.to(defaultDirectExchange())
.with("default.repeat.trade.queue");
} }
生产者:
package com.wjy.delaymq; import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class Sender {
@Autowired
private RabbitTemplate rabbitTemplate; public void send(QueueMessage message) {
//即时消息
if(message.getType() == 10){
sendMessage(message.getExchange(),message.getQueueName(),message.getMessage());
}
//延时消息
if(message.getType() == 20){
sendTimeMessage(message);
}
} //发送即时消息;
private void sendMessage(String exchange,String queueName,String msg){
rabbitTemplate.convertAndSend(exchange,queueName, msg);
} //发送延时消息;
public void sendTimeMessage(QueueMessage message) {
int seconds = message.getSeconds();
// 直接发送,无需进入死信队列
if(seconds <= 0){
sendMessage(message.getExchange(),message.getQueueName(), message.getMessage());
}else{
//rabbit默认为毫秒级
long times = seconds * 1000;
//这里需要字符定义延时处理器;
MessagePostProcessor processor = new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setExpiration(times + "");
return message;
}
};
//注意传送的消息必须是字串串或者 字节或者实现序列化的对象
//否则报错:Execution of Rabbit message listener failed
//改完后将之前的队列数据清除 否则还会报错
rabbitTemplate.convertAndSend("default.direct.exchange","default.dead.letter.queue", "转发消息", processor);
}
} }
消费者:
package com.wjy.delaymq; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
@RabbitListener(queues = "default.repeat.trade.queue")
public class TradeRecever {
@Autowired
private Sender sender; @RabbitHandler
public void process(String content) {
System.err.println("-----------延时结束--------------"+content);
QueueMessage message = new QueueMessage("app.queue.hello", "转发消息...");
message.setType(10);
sender.send(message);
}
}
package com.wjy.delaymq; import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; @Component
@RabbitListener(queues = "app.queue.hello")
public class HelloRecever { @RabbitHandler
public void process(String content) { System.err.println("hello 接受消息:" + content);
}
}
POJO:
package com.wjy.delaymq; import java.io.Serializable;
import java.util.Date; public class QueueMessage implements Serializable {
private String exchange; private String queueName; private Integer type; private Integer group; private Date timestamp; private String message; private Integer status; private int retry = 0; private int maxRetry = 10; private int seconds = 1; public QueueMessage() {
super();
} public QueueMessage(String queueName, String message) {
super();
this.queueName = queueName;
this.message = message;
this.exchange = "default.direct.exchange";
this.type = 10;
this.group = 10;
this.timestamp = new Date();
this.status = 10;
} public String getExchange() {
return exchange;
} public void setExchange(String exchange) {
this.exchange = exchange;
} public String getQueueName() {
return queueName;
} public void setQueueName(String queueName) {
this.queueName = queueName;
} public Integer getType() {
return type;
} public void setType(Integer type) {
this.type = type;
} public Integer getGroup() {
return group;
} public void setGroup(Integer group) {
this.group = group;
} public Date getTimestamp() {
return timestamp;
} public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
} public String getMessage() {
return message;
} public void setMessage(String message) {
this.message = message;
} public Integer getStatus() {
return status;
} public void setStatus(Integer status) {
this.status = status;
} public int getRetry() {
return retry;
} public void setRetry(int retry) {
this.retry = retry;
} public int getMaxRetry() {
return maxRetry;
} public void setMaxRetry(int maxRetry) {
this.maxRetry = maxRetry;
} public int getSeconds() {
return seconds;
} public void setSeconds(int seconds) {
this.seconds = seconds;
}
}
测试类:
package com.wjy.delaymq; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
public class DelayTest { @Autowired
private Sender sender; @Test
public void delaySendTest() {
System.err.println("发送延迟消息...");
QueueMessage message = new QueueMessage("app.queue.hello", "测试延时消息...");
//20代表延时消息队列;
message.setType(20);
//设置延时时间,单位为毫秒;
message.setSeconds(6);
sender.send(message);
try {
Thread.sleep(600000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
七、消息确认机制
配置类:
package com.wjy.ack; 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; @Configuration
public class AckRabbitConfig { /**
* 定义一个hello的队列
* Queue 可以有4个参数
* 1.队列名
* 2.durable 持久化消息队列 ,rabbitmq重启的时候不需要创建新的队列 默认true
* 3.auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
* 4.exclusive 表示该消息队列是否只在当前connection生效,默认是false
*/
@Bean
public Queue helloQueue() {
return new Queue("queue-test");
} /** ======================== 定制一些处理策略 =============================*/ /**
* Fanout 就是我们熟悉的广播模式或者订阅模式,给Fanout交换机发送消息,绑定了这个交换机的所有队列都收到这个消息。
* @return
*/
@Bean
public FanoutExchange fanoutExchange() {
return new FanoutExchange("ABExchange");
} @Bean
public Binding bindingExchangeA(Queue helloQueue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(helloQueue).to(fanoutExchange);
} }
生产者:
package com.wjy.ack; import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.util.Date; @Component
public class Producer implements RabbitTemplate.ReturnCallback {
@Autowired
private RabbitTemplate rabbitTemplate; /**
* 给hello队列发送消息
*/
public void send() {
String context = "你好现在是 " + new Date() +"";
System.err.println("HelloSender发送内容 : " + context);
this.rabbitTemplate.setReturnCallback(this);
this.rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
if (!ack) {
System.out.println("HelloSender消息发送失败" + cause + correlationData.toString());
} else {
System.out.println("HelloSender 消息发送成功 ");
}
}); rabbitTemplate.convertAndSend("queue-test", context);
} @Override
public void returnedMessage(Message message, int i, String s, String s1, String s2) {
System.err.println("sender return success" + message.toString()+"==="+i+"==="+s1+"==="+s2);
}
}
消费者:
package com.wjy.ack; import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component; import java.io.IOException; @Component
@RabbitListener(queues = "queue-test")
public class Comsumer { @RabbitHandler
public void process(String msg,Message message, Channel channel) throws IOException {
try {
// 采用手动应答模式, 手动确认应答更为安全稳定
/*channel.basicAck(deliveryTag,ack)
deliveryTag-当前消息的类似编号的号码,服务端为每一个消息生成的类似编号的号码
ack-false只确认当前一个消息收到,true确认所有consumer获得的消息
*/
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
System.err.println("receive: " + new String(message.getBody()));
}
catch (Exception e){
//丢弃这条消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false);
//拒绝这条消息
//channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
}
}
}
测试类:
package com.wjy.ack; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqAckTests {
@Autowired
private Producer producer; /**
* @Desc: 测试之前需在application.yml开启消息确认的配置
*/
@Test
public void send() {
producer.send();
}
}
参考:
【RabbitMQ学习之二】RabbitMQ四种交换机模式应用的更多相关文章
- rabbitmq系列(二)几种常见模式的应用场景及实现
一.简单模式 原理:生产者将消息交给默认的交换机,交换机获取消息后交给绑定这个生产者的队列(投递规则为队列名称和routing key 相同的队列),监听当前队列的消费者获取信息并执行消费逻辑. 场景 ...
- RabbitMQ四种交换机类型介绍
RabbitMQ 原文地址: https://baijiahao.baidu.com/s?id=1577456875919174629&wfr=spider&for=pc 最新版本的 ...
- ActiveMQ、RabbitMQ、RocketMQ、Kafka四种消息中间件分析介绍
ActiveMQ.RabbitMQ.RocketMQ.Kafka四种消息中间件分析介绍 我们从四种消息中间件的介绍到基本使用,以及高可用,消息重复性,消息丢失,消息顺序性能方面进行分析介绍! 一.消息 ...
- Rabbitmq的几种交换机模式
Rabbitmq的核心概念(如下图所示):有虚拟主机.交换机.队列.绑定: 交换机可以理解成具有路由表的路由程序,仅此而已.每个消息都有一个称为路由键(routing key)的属性,就是一个简单的字 ...
- RabbitMQ学习系列二-C#代码发送消息
RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...
- 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用
目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...
- 设计模式学习(二十四):Spring 中使用到的设计模式
设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...
- 从零学习Fluter(八):Flutter的四种运行模式--Debug、Release、Profile和test以及命名规范
从零学习Fluter(八):Flutter的四种运行模式--Debug.Release.Profile和test以及命名规范 好几天没有跟新我的这个系列文章,一是因为这两天我又在之前的基础上,重新认识 ...
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...
随机推荐
- 虚拟机Ubuntu18.04 root下 连接 windows 中 winScp
先查看自己虚拟机中是否有 ssh服务 如果没有的话先安装 apt-get install openssh-server 安装完之后 先手动开启一下服务 /etc/init.d/ssh restart ...
- gentelella 开源后台使用记录
前言 gentelella是一款开源后台,github地址是:https://github.com/ColorlibHQ/gentelella 使用 表单验证 parsley 验证 在form.htm ...
- [個人紀錄] postgre dump出table 再用psql還原
--dump tablepg_dump --host #server --port 5432 --username #username --format plain --ignore-version ...
- Flask基于websocket的简单聊天室
1.安装gevent-websocket pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ gevent-websocket 2.cha ...
- Linux下Mysql5.7忘记密码
一.问题 linux下的mysql5.7忘记密码 二.解决 第一步:打开mysql5.7的配置文件my.cnf,并在里面增加一行:skip-grant-tables 保存并退出(:wq) [roo ...
- 配置Java,jdk环境变量
注意:所有的都是配系统变量 变量名:JAVA_HOME 变量值:D:\Program Files\Java\jdk1.8.0_202(以自己的为准)变量名:Path 变量值:%JAVA_HOME%\b ...
- android studio学习---模板
Android Studio还为开发人员提供多种模板选项,从而大大提升开发速度.这些模板能自动创建Activity以及必要的XML文件.大家还可以利用这些模板创建出较为基础的Android应用程序,并 ...
- Linux的权限管理操作-Linux从入门到精通第七天(非原创)
文章大纲 一.权限概述二.权限设置三.属主与属组设置四.扩展五.学习资料下载六.参考文章 一.权限概述 总述:Linux系统一般将文件可存/取访问的身份分为3个类别:owner.group.other ...
- 1047--Remove All Adjacent Duplicates In String
public class RemoveAllAdjacentDuplicatesInString { /* 解法一:栈 */ public String removeDuplicates(String ...
- javascript之BOM对象(二location对象)
一.location对象提供和当前加载的文档相关的信息还有一些导航功能.location对象是window对象的属性,同时也是document对象的属性.window.location和documen ...