环境说明
centos8+springcloudalibaba+rabbitmq
安装
下载安装并使用
rabbitmq-plugins enable rabbitmq_management
启动管理后台
安装完成
搭建
pom.xml
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
yml配置
server:
port: 8601
spring:
application:
name: client1-service
cloud:
nacos:
#192.168.82.83:8848
server-addr: 127.0.0.1:8848
datasource:
#新com.mysql.cj.jdbc.Driver 老com.mysql.jdbc.Driver
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3310/client1_service?serverTimezone=GMT%2B8&useSSL=true
username: root
password: 123456
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
简单普通消息队列
注入消息队列配置
直接创建消息队列,或使用默认交换机,具体详见rabbitmq解析
@Configuration
public class RabbitMqConfig {
/**
* 简单消息队列
*/
public static final String SIMPLEMSG = "clent1.simple";
@Bean
public Queue simpleMsgQueue() {
Queue queue = new Queue(SIMPLEMSG);
// 是否持久化
queue.isDurable();
// 仅创建者可以使用的私有队列,断开后自动删除
queue.isExclusive();
// 当所有消费客户端连接断开后,是否自动删除队列
queue.isAutoDelete();
return queue;
}
}
发送者
@Component
@Slf4j
public class Sender {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendSimpleMsg(String message) {
Message messageObject = MessageBuilder.withBody(message.getBytes()).setMessageId(String.valueOf(123)).build();
//amqpTemplate.convertAndSend(RabbitMqConfig.SIMPLEMSG,message);
amqpTemplate.convertAndSend(RabbitMqConfig.SIMPLEMSG,messageObject);
}
}
消费者
@Component
public class Receiver {
@RabbitListener(queues = {RabbitMqConfig.SIMPLEMSG})
public void simpleQueue(Message message) {
String s = new String(message.getBody());
System.out.println("接收简单消息队列消息:"+s);
System.out.println("消息id为:"+message.getMessageProperties().getMessageId());
}
}
延时消息队列
配置
package org.example.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* @author shock wave 2
* @version 1.0
* @description: TODO
* @date 2021/7/26 15:32
*/
@Configuration
public class RabbitMqConfig {
/**
* 简单消息队列
*/
public static final String SIMPLEMSG = "clent1.simple#";
/**
* 延时消息队列
*/
public static final String DELAY_SIMPLEMSG = "clent1.simple.delay";
public static final String SIMPLEMSG_QUEUE = "simple.queue";
/**
* 交换机名
*/
public static final String DELAY_SIMPLEMSG_EXCHANGE = "clent1.simple.delay.exchange";
/**
* 死信路由key
*/
public static final String DELAY_SIMPLEMSG_ROUTER_KEY = "simple.delay.key";
/**
* 普通路由key
*/
public static final String SIMPLEMSG_ROUTER_KEY = "delay.key";
/**
* @description: TODO 普通家谱换季
*/
public static final String SIMPLEMSG_EXCHANGE = "simple.exchange";
@Bean
public Queue simpleMsgQueue() {
Queue queue = new Queue(SIMPLEMSG);
// 是否持久化
queue.isDurable();
// 仅创建者可以使用的私有队列,断开后自动删除
queue.isExclusive();
// 当所有消费客户端连接断开后,是否自动删除队列
queue.isAutoDelete();
return queue;
}
@Bean
public Queue delaySimpleMsgQueue() {
Queue queue = new Queue(SIMPLEMSG_QUEUE,true);
return queue;
}
/**
* 延迟队列配置
* <p>
* 1、params.put("x-message-ttl", 5 * 1000);
* 第一种方式是直接设置 Queue 延迟时间 但如果直接给队列设置过期时间,这种做法不是很灵活,(当然二者是兼容的,默认是时间小的优先)
* 2、rabbitTemplate.convertAndSend(book, message -> {
* message.getMessageProperties().setExpiration(2 * 1000 + "");
* return message;
* });
* 第二种就是每次发送消息动态设置延迟时间,这样我们可以灵活控制
**/
@Bean
public Queue delayQueue() {
Map<String, Object> params = new HashMap<>();
// x-dead-letter-exchange 声明了队列里的死信转发到的DLX名称,
params.put("x-dead-letter-exchange", SIMPLEMSG_EXCHANGE);
// x-dead-letter-routing-key 声明了这些死信在转发时携带的 routing-key 名称。
params.put("x-dead-letter-routing-key", SIMPLEMSG_ROUTER_KEY);
return new Queue(DELAY_SIMPLEMSG, true, false, false, params);
}
/**
* 需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。
* 这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “dog”,则只有被标记为“dog”的消息才被转发,
* 不会转发dog.puppy,也不会转发dog.guard,只会转发dog。
* @return DirectExchange
*/
@Bean
public DirectExchange orderDelayExchange() {
//无使用自动删除
return new DirectExchange(DELAY_SIMPLEMSG_EXCHANGE,true,false);
}
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(delayQueue()).to(orderDelayExchange()).with(DELAY_SIMPLEMSG_ROUTER_KEY);
}
/**
* 将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。
* 符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。
**/
@Bean
public TopicExchange orderTopicExchange() {
return new TopicExchange(SIMPLEMSG_EXCHANGE,true,false);
}
@Bean
public Binding orderBinding() {
// TODO 如果要让延迟队列之间有关联,这里的 routingKey 和 绑定的交换机很关键
return BindingBuilder.bind(delaySimpleMsgQueue()).to(orderTopicExchange()).with(SIMPLEMSG_ROUTER_KEY);
}
}
发送者
package org.example.rabbitmq;
import lombok.extern.slf4j.Slf4j;
import org.example.config.RabbitMqConfig;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author shock wave 2
* @version 1.0
* @description: TODO
* @date 2021/7/26 15:26
*/
@Component
@Slf4j
public class Sender {
@Autowired
private AmqpTemplate amqpTemplate;
public void sendSimpleMsg(String message) {
Message messageObject = MessageBuilder.withBody(message.getBytes()).setMessageId(String.valueOf(123)).build();
//amqpTemplate.convertAndSend(RabbitMqConfig.SIMPLEMSG,message);
amqpTemplate.convertAndSend(RabbitMqConfig.SIMPLEMSG,messageObject);
}
/**
* 红包延时消息队列
* @Param
* @return
*/
public void sendSimpleDelayMsg(String message) {
amqpTemplate.convertAndSend(RabbitMqConfig.DELAY_SIMPLEMSG_EXCHANGE, RabbitMqConfig.DELAY_SIMPLEMSG_ROUTER_KEY, message, msg -> {
msg.getMessageProperties().setExpiration("3000");
return msg;
});
}
}
消费者
package org.example.rabbitmq;
import groovy.util.logging.Log;
import groovy.util.logging.Slf4j;
import org.example.config.RabbitMqConfig;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author shock wave 2
* @version 1.0
* @description: TODO
* @date 2021/7/26 15:26
*/
@Component
public class Receiver {
@RabbitListener(queues = {RabbitMqConfig.SIMPLEMSG})
public void simpleQueue(Message message) {
String s = new String(message.getBody());
System.out.println("接收简单消息队列消息:"+s);
System.out.println("消息id为:"+message.getMessageProperties().getMessageId());
}
@RabbitListener(queues = {RabbitMqConfig.SIMPLEMSG_QUEUE})
public void simpleDelayQueue(Message message) {
String s = new String(message.getBody());
System.out.println("接收延时消息队列消息:"+s);
System.out.println("消息id为:"+message.getMessageProperties().getMessageId());
}
}
其他补充
1、配置文件自动刷新
如果使用springcloudnetflix开发微服务(springcloudalibaba可以直接使用@RefreshScope,自动刷新配置),结合@RefreshScope+springcloud Acturator可以刷新配置文件,但是还是需要调用acturator接口刷新配置,这里可以使用springcloudbus结合rabbitmq,实现自动刷新,实际就是一个订阅/通知
具体可以参考spring.io/projects/sp…
2、spring-cloud-stream使用rabbitmq
springcloudnetflix可以使用spring-cloud-stream连接rabbitmq,Spring Cloud Stream是用于构建消息驱动的微服务应用程序的框架。Spring Cloud Stream在Spring Boot的基础上创建了独立的生产级Spring应用程序,并使用Spring Integration提供了到消息代理的连接。它提供了来自多家供应商的中间件的合理配置,并介绍了持久性发布-订阅语义,使用者组和分区的概念。具体参考spring.io/projects/sp…