环境
  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();
}
}

演示代码

参考:

springboot集成rabbitmq(实战)

延时队列

5种消息队列

RabbitMQ四种交换机类型介绍

【RabbitMQ学习之二】RabbitMQ四种交换机模式应用的更多相关文章

  1. rabbitmq系列(二)几种常见模式的应用场景及实现

    一.简单模式 原理:生产者将消息交给默认的交换机,交换机获取消息后交给绑定这个生产者的队列(投递规则为队列名称和routing key 相同的队列),监听当前队列的消费者获取信息并执行消费逻辑. 场景 ...

  2. RabbitMQ四种交换机类型介绍

    RabbitMQ  原文地址: https://baijiahao.baidu.com/s?id=1577456875919174629&wfr=spider&for=pc 最新版本的 ...

  3. ActiveMQ、RabbitMQ、RocketMQ、Kafka四种消息中间件分析介绍

    ActiveMQ.RabbitMQ.RocketMQ.Kafka四种消息中间件分析介绍 我们从四种消息中间件的介绍到基本使用,以及高可用,消息重复性,消息丢失,消息顺序性能方面进行分析介绍! 一.消息 ...

  4. Rabbitmq的几种交换机模式

    Rabbitmq的核心概念(如下图所示):有虚拟主机.交换机.队列.绑定: 交换机可以理解成具有路由表的路由程序,仅此而已.每个消息都有一个称为路由键(routing key)的属性,就是一个简单的字 ...

  5. RabbitMQ学习系列二-C#代码发送消息

    RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...

  6. 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用

    目录 学习笔记:CentOS7学习之二十四:expect-正则表达式-sed-cut的使用 24.1 expect实现无交互登录 24.1.1 安装和使用expect 24.2 正则表达式的使用 24 ...

  7. 设计模式学习(二十四):Spring 中使用到的设计模式

    设计模式学习(二十四):Spring 中使用到的设计模式 作者:Grey 原文地址: 博客园:设计模式学习(二十四):Spring 中使用到的设计模式 CSDN:设计模式学习(二十四):Spring ...

  8. 从零学习Fluter(八):Flutter的四种运行模式--Debug、Release、Profile和test以及命名规范

    从零学习Fluter(八):Flutter的四种运行模式--Debug.Release.Profile和test以及命名规范 好几天没有跟新我的这个系列文章,一是因为这两天我又在之前的基础上,重新认识 ...

  9. python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法

    python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...

随机推荐

  1. 关于wordpress4.8中的Twenty Seventeen主题的主题选项增加章节的实现

    我这里的wordpress版本是4.8  默认的主题是 Twenty Seventeen 我想实现的事 主题选项的首页  多增加2个章节 默认是只有4个章节  我想在增加2个 到6个 看下实现后的效果 ...

  2. Markdown温故知新(3):六个实用扩展语法

    目录 1.表格(Table) 2.待办事项或清单(To Do List) 3.自动目录 TOC 4.流程图 5.时序图 6.甘特图 7.总结 1.表格(Table) 没用过 Markdown 表格的人 ...

  3. rabbitMq 学习笔记(一)

    消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题 实现高性能,高可用,可伸缩和最终一致性架构. RabbitMQ 是采用 Erlang 语言实现 AMQP (Adva ...

  4. 《2017年-2018年中国MES软件及服务市场研究报告》正式发布!

    <2017年-2018年中国MES软件及服务市场研究报告>由e-works Research研究编写,报告深度分析了2017年及2018年中国MES市场发展状况,从市场规模.市场特点.需求 ...

  5. .NET Core中 实现H5微信登录(静默授权方式)

    需求 假设现在有一个H5需要有微信登录.手机号登录.邮箱登录 三种登录方式.让我们一起来看看微信登录如何实现吧 界面: 最终实现的效果图(登录成功后返回个人页): 因为微信登录目前没有实现移动端的其他 ...

  6. Centos7配置ssh免密登录群发

    ssh免密登录是客户端发送自己的公钥到服务器.用公钥进行解密,自己生成的私钥进行加密. 首先在客户端查看sshd服务是否启动 [zhiwei@zhiwei1 ~]$ ps -Af|grep sshd; ...

  7. Django使用Mysql已存在数据表的方法

    在mysql数据库中已经存在有数据的表,自己又不想删除,下面方法可以同步django中创建的表 1.最好将自己建的表名改为前缀和django自动创建表名前缀相同,不改也可以,但是后期表太多容易混乱 2 ...

  8. MySQL读写分离之MyCAT

    Mycat实现MySQL主从复制读写分离 MyCAT的安装及部署 1.部署jdk环境 MyCAT用Java开发,需要有JAVA运行环境,mycat依赖jdk1.7的环境 1)上传jdk [root@l ...

  9. javascript之BOM对象(二location对象)

    一.location对象提供和当前加载的文档相关的信息还有一些导航功能.location对象是window对象的属性,同时也是document对象的属性.window.location和documen ...

  10. 随笔记录--RegExp类型

    阅读Javascript高级程序设计第五章 -- RegExp类型总结 对于基础教程部分, 有小伙伴不熟悉的,可以参考 正则表达式 - 教程 1. 基础部分回顾: ECMASript通过RegExp类 ...