一、Springboot整合RabbitMQ
1.1 添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
1.2 application.yml
rabbitmq: host: 192.168.31.128 port: 5672 username: mqroot password: mqroot virtual-host: test # 消息确认类型 NONE 默认值 禁止发布调用模式 correlated 发布消息成功到交换器后会触发回调方 法 publisher-confirm-type: correlated # 设置允许消息从交换机路由到队列失败时的回调 默认值是false 即不执行回调 publisher-returns: true listener: direct: # 手动ack 默认值是auto 自动确认 manual 是手动确认 acknowledge-mode: manual
1.3 rabbitmq配置类
Queue参数信息
-
name: 队列的名称;
-
actualName: 队列的真实名称,默认用name参数,如果name为空,则根据规则生成一个;
-
durable: 是否持久化;
-
exclusive: 是否独享、排外的;
-
autoDelete: 是否自动删除;
-
arguments:队列的其他属性参数,有如下可选项,可参看图2的arguments:
-
x-message-ttl:消息的过期时间,单位:毫秒;
-
x-expires:队列过期时间,队列在多长时间未被访问将被删除,单位:毫秒;
-
x-max-length:队列最大长度,超过该最大值,则将从队列头部开始删除消息;
-
x-max-length-bytes:队列消息内容占用最大空间,受限于内存大小,超过该阈值则从队列头部开始删除消息;
-
x-overflow:设置队列溢出行为。这决定了当达到队列的最大长度时消息会发生什么。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁队列类型仅支持drop-head;
-
x-dead-letter-exchange:死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中;
-
x-dead-letter-routing-key:死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值
-
x-single-active-consumer:表示队列是否是单一活动消费者,true时,注册的消费组内只有一个消费者消费消息,其他被忽略,false时消息循环分发给所有消费者(默认false)
-
x-max-priority:队列要支持的最大优先级数;如果未设置,队列将不支持消息优先级;
-
x-queue-mode(Lazy mode):将队列设置为延迟模式,在磁盘上保留尽可能多的消息,以减少RAM的使用;如果未设置,队列将保留内存缓存以尽可能快地传递消息;
-
x-queue-master-locator:在集群模式下设置镜像队列的主节点信息。
-
交换机参数信息
类型
-
FanoutExchange :扇形 交换机
-
DirectExchange :直连交换机 routing模式用的交换机
-
TopicExchange :主题模式交换机
参数信息
-
name:交换机名称
-
durable:是否把交换机持久化到磁盘上
-
autoDelete :是否自动删除交换机 用法有点类似上面的队列中的autoDelete 只有所有队列都和交换机接触订阅,说白了就是所有绑定到交换机上的队列不再需要改交换机,他就该死了,有点残酷
-
artuments :额外参数
配置类
@Configuration public class RabbitMQConfig { public static final String EX_CHANGE = "ex.direct"; public static final String ORDER_QUEUE = "order.queue"; public static final String ORDER_QUEUE_KEY = "order"; public static final String DLL_ORDER_QUEUE = "ddl.order.queue"; public static final String DLL_ORDER_QUEUE_KEY = "ddl.order"; @Bean("exDirect") public DirectExchange initExchange() { // new FanoutExchange() return new DirectExchange(EX_CHANGE, true, false); } @Bean("orderQueue") public Queue initOrderQueue() { // 设置有效期 HashMap<String, Object> map = new HashMap<>(); map.put("x-message-ttl",10000); map.put("x-dead-letter-exchange",EX_CHANGE); map.put("x-dead-letter-routing-key",DLL_ORDER_QUEUE_KEY); map.put("x-overflow","reject-publish"); return new Queue(ORDER_QUEUE,true); } @Bean("ddlOrderQueue") public Queue initDDLOrderQueue() { return new Queue(DLL_ORDER_QUEUE,true); } // 绑定 @Bean("bindingQueue") public Binding bindingQueue(@Qualifier("orderQueue") Queue queue,@Qualifier("exDirect") DirectExchange exchange){ return BindingBuilder.bind(queue).to(exchange).with(ORDER_QUEUE_KEY); } @Bean("bindingDDLQueue") public Binding bindingDDLQueue(@Qualifier("ddlOrderQueue") Queue queue,@Qualifier("exDirect") DirectExchange exchange){ return BindingBuilder.bind(queue).to(exchange).with(DLL_ORDER_QUEUE_KEY); } /* --------------------------------------- --------------其他类型交换机配置类似------- --------------------------------------- */ /** * 将队列和交换机绑定, 并设置用于匹配键 * @return */ @Bean public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory) { /* ConfirmCallback是用来得知是否进入到交换机 ReturnCallback是获取未进入队列的回调信息,如果成功进入队列,不会进入这个回调方法。必须设置rabbitTemplate.setMandatory(true); */ RabbitTemplate rabbitTemplate = new RabbitTemplate(); rabbitTemplate.setConnectionFactory(connectionFactory); // 消息进入到MQ触发,是否到交换机 rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { System.out.println("ConfirmCallback:相关数据:" + correlationData); System.out.println("ConfirmCallback:确认情况:" + ack); System.out.println("ConfirmCallback:原因:" + cause); } }); // 设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数 // 为true时,消息通过交换器无法匹配到队列会返回给生产者,并触发MessageReturn,为false时,匹配不到会直接被丢弃 rabbitTemplate.setMandatory(true); // 消息未进入队列时触发回调 rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() { @Override public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) { System.out.println("ReturnCallback:消息:" + message); System.out.println("ReturnCallback:回应码:" + replyCode); System.out.println("ReturnCallback:回应信息:" + replyText); System.out.println("ReturnCallback:交换机:" + exchange); System.out.println("ReturnCallback:路由键:" + routingKey); } }); return rabbitTemplate; } }
1.4 生产者
@RestController public class RabbitMQProductController { @Resource RabbitTemplate rabbitTemplate; @PostMapping("send") public String send() { String messageId = String.valueOf(UUID.randomUUID()); String messageData = "test message, hello!"; String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); Map<String, Object> map = new HashMap<>(); map.put("messageId", messageId); map.put("messageData", messageData); map.put("createTime", createTime); //将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchange rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting", map); return "ok"; } }
1.5 消费者
@RabbitListener添加给类
@Component @RabbitListener(queues = "TestDirectQueue")//监听的队列名称 TestDirectQueue public class DirectReceiver { @RabbitHandler public void process(Map testMessage, Message message, Channel channel) throws IOException { System.out.println("DirectReceiver消费者收到消息 : " + testMessage.toString()); System.out.println(message); // 手动应答 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); } }
@RabbitListener添加给方法
/** * 消费者:监听队列,从队列中获取消息,并处理消息 */ @Component public class DirectListener2 { /** * * @param msg:获取到的消息,类型与发布时的类型一致 * @param message:消息的详细信息:消息内容body,存储信息(队列,交换机,路由,标识符) * @param channel:信道 */ @RabbitListener(queues = RabbitMQConfig.DIRECT_EXCHANGE_QUEUE) public void handleMyQueue(Map msg, Message message, Channel channel) throws IOException { System.out.println("队列my-queue的信息"); System.out.println(msg.toString()); System.out.println(message); System.out.println(channel); // 手动应答 channel.basicAck(message.getMessageProperties().getDeliveryTag(),true); } @RabbitListener(queues = "aaa") public void handleAAA(String msg, Message message, Channel channel) throws IOException { System.out.println("队列aaa的信息"); System.out.println(msg.toString()); System.out.println(message); System.out.println(channel); // 手动应答 channel.basicAck(message.getMessageProperties().getDeliveryTag(),true); } }