赞
踩
目录
- <dependencies>
- <!-- springboot-web组件 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <!-- 添加springboot对amqp的支持 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-amqp</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- </dependency>
- <!--fastjson -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.49</version>
- </dependency>
-
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- </dependency>
- </dependencies>
- spring:
- rabbitmq:
- #连接地址
- host: 127.0.0.1
- #端口号
- port: 5672
- #账号
- username: guest
- #密码
- password: guest
- #虚拟主机
- virtual-host: /rkVirtualHost
- server:
- port: 8080
-
- package com.rk.config;
- 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 :Rk.
- * @date : 2022/10/8
- * 定义完成后 rabbitmq服务器会自动创建交换机和队列 以及绑定关系
- */
- @Configuration
- public class RabbitMQConfig {
-
-
- /**
- * 定义交换机名称
- */
- private String EXCHANGE_NAME="springboot_falout_exchange";
-
- /**
- * 短信队列
- */
- private String FANOUT_SMS_QUEUE = "fanout_sms_queuerk";
-
- /**
- * 邮件队列
- */
- private String FANOUT_EMAIL_QUEUE = "fanout_email_queuerk";
-
-
- /**
- * 定义 扇形交换机
- */
- @Bean
- public FanoutExchange fanoutExchange(){
- //参数 交换机名称
- return new FanoutExchange(EXCHANGE_NAME);
- }
-
- /**
- *参数一:队列名称
- *参数二durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
- *参数三exclusive:默认也是false,是否独占队列
- *参数四autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
- */
- @Bean
- public Queue smsQueue(){
- return new Queue(FANOUT_SMS_QUEUE,true, false,false);
- }
-
- /**
- *参数一:队列名称
- *参数二:durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
- *参数三:exclusive:默认也是false,是否独占队列
- *参数四:autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
- */
- @Bean
- public Queue emailQueue(){
- return new Queue(FANOUT_EMAIL_QUEUE,true,false,false);
- }
-
- /**
- * 短信队列绑定交换机
- * @param smsQueue 短信队列注入到容器的id,也就是方法名 sumQueue
- * @param fanoutExchange 交换机注入到容器的id,也就是方法名 fanoutExchange
- * @return
- */
- @Bean
- public Binding bindingSmsFanoutExchange(Queue smsQueue,FanoutExchange fanoutExchange){
- return BindingBuilder.bind(smsQueue).to(fanoutExchange);
- }
-
- /**
- * 邮件队列队列绑定交换机
- * @param emailQueue 短信队列注入到容器的id,也就是方法名 emailQueue
- * @param fanoutExchange 交换机注入到容器的id,也就是方法名 fanoutExchange
- * @return
- */
- @Bean
- public Binding bindingEmailFanoutExchange(Queue emailQueue,FanoutExchange fanoutExchange){
- return BindingBuilder.bind(emailQueue).to(fanoutExchange);
- }
-
- }
这里使用的是扇形交换机,交换机会把消息路由到绑定到它的所有队列。
在Spring启动时,利用Spring Bean管理工厂BeanFactory接口,实现动态
创建交换机
、队列
、交换机和队列的绑定关系
,让我们无需进行重复的编码工作。
- package com.rk.controller;
- import com.rk.domain.User;
- import org.springframework.amqp.core.AmqpTemplate;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- */
-
- @RestController
- public class FanoutProducerController {
-
- @Autowired
- private AmqpTemplate amqpTemplate;
-
- /**
- * 模拟注册接口
- * @param
- * @return
- */
- @GetMapping("/registered")
- public String sendMsg(){
-
- User user=new User("rk",22,"男","陕西西安");
- //1、将user存入数据库
-
- //2、发送邮件和短信
- //投递消息到交换机 交换机将消息路由到邮件队列和短信队列
-
- /**
- * 参数一 交换机名称
- * 参数二 路由key
- * 参数三 发送内容
- */
- amqpTemplate.convertAndSend("springboot_falout_exchange","",user);
-
- return "注册完成";
- }
-
- }
这里直接发送的user对象,必须要将user对象实现Serializable接口。
- import com.rk.domain.User;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.amqp.rabbit.annotation.RabbitHandler;
- import org.springframework.amqp.rabbit.annotation.RabbitListener;
- import org.springframework.stereotype.Component;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- /* */
- @Slf4j
- @Component
- @RabbitListener(queues = "fanout_email_queuerk") //监听队列
- public class EmailConsumer {
-
- //监听到队列消息后执行
- @RabbitHandler
- public void process(User user) {
- System.err.println("邮件消费者接收到消息发送邮件:"+user);
- }
-
- }
- import com.rk.domain.User;
- import org.springframework.amqp.rabbit.annotation.RabbitHandler;
- import org.springframework.amqp.rabbit.annotation.RabbitListener;
- import org.springframework.stereotype.Component;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- */
-
- @Component
- @RabbitListener(queues = "fanout_sms_queuerk")
- public class SumConsumer {
- @RabbitHandler
- public void process(User user){
- System.out.println("短信消费者接收到消息发送短信:"+user);
- }
- }
访问注册接口,会立即响应。
邮件消费者1:
- import com.rk.domain.User;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.amqp.rabbit.annotation.RabbitHandler;
- import org.springframework.amqp.rabbit.annotation.RabbitListener;
- import org.springframework.stereotype.Component;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- /* */
- @Slf4j
- @Component
- @RabbitListener(queues = "fanout_email_queuerk") //监听队列
- public class EmailConsumer1 {
-
-
- //监听到队列消息后执行
- @RabbitHandler
- public void process(User user) throws InterruptedException {
- //休眠10ms 模拟处理时间
- Thread.sleep(10);
- System.err.println("邮件消费者1接收到消息发送邮件:"+user);
- }
-
- }
邮件消费者2:
- import com.rk.domain.User;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.amqp.rabbit.annotation.RabbitHandler;
- import org.springframework.amqp.rabbit.annotation.RabbitListener;
- import org.springframework.stereotype.Component;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- /* */
- @Slf4j
- @Component
- @RabbitListener(queues = "fanout_email_queuerk")
- public class EmailConsumer2 {
-
- @RabbitHandler
- public void process(User user) throws InterruptedException {
- //休眠20ms 模拟处理时间
- Thread.sleep(20);
- System.out.println("邮件消费者2接收到消息发送邮件:"+user);
- }
-
- }
测试: 生产者往交换机发送20条消息:
两个消费者使用轮询的方式对消息进行消费,而且不存在重复消费。 这里消费者1的处理时间是10ms,消费者2的处理时间为20ms,所以使用轮询的方式来进行消费并不合理,需要实现能者多劳。
更改配置文件的参数来解决这一个问题:
邮件消费者1:
- package com.rk.service;
- import com.rabbitmq.client.Channel;
- import com.rk.domain.User;
- import lombok.extern.slf4j.Slf4j;
- 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;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- /* */
- @Slf4j
- @Component
- @RabbitListener(queues = "fanout_email_queuerk")
- public class EmailConsumer1 {
-
- @RabbitHandler
- public void process(User user, Message message, Channel channel) throws IOException {
- try {
- //休眠20ms 模拟处理时间
- Thread.sleep(10);
- System.err.println("邮件消费者1接收到消息发送邮件:"+user);
- //确认一条消息
- channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
- }catch (Exception e){
- //消费者告诉队列信息消费失败
- /**
- * 拒绝确认消息:
- * channel.basicNack(long deliveryTag, boolean multiple, boolean requeue) ;
- * deliveryTag:该消息的index
- * multiple:是否批量true:将一次性拒绝所有小于deliveryTag的消息
- * requeue:被拒绝的是否重新入队列
- */
- channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
- }
- }
- }
邮件消费者2:
- import com.rabbitmq.client.Channel;
- import com.rk.domain.User;
- import lombok.extern.slf4j.Slf4j;
- 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;
-
- /**
- * @author :Rk.
- * @date : 2022/10/8
- /* */
- @Slf4j
- @Component
- @RabbitListener(queues = "fanout_email_queuerk")
- public class EmailConsumer4 {
-
- @RabbitHandler
- public void process(User user, Message message, Channel channel) throws IOException {
- try {
- //确认一条消息
- channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
- //休眠20ms 模拟处理时间
- Thread.sleep(20);
- System.out.println("邮件消费者2接收到消息发送邮件:"+user);
- }catch (Exception e){
- //消费者告诉队列信息消费失败
- /**
- * 拒绝确认消息:
- * channel.basicNack(long deliveryTag, boolean multiple, boolean requeue) ;
- * deliveryTag:该消息的index
- * multiple:是否批量true:将一次性拒绝所有小于deliveryTag的消息
- * requeue:被拒绝的是否重新入队列
- */
- channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
- }
- }
-
- }
实现能者多劳和手动确认。上面的演示过程都是将生产者和消费者写在同一个项目中,在实际开发过程中,一般使用2个项目,一个项目来投递消息,一个专门用来消费消息,使用不同的JVM来运行生产者和消费者。
整合直连交换机和主题交换机可以看下面这篇博客:
Springboot 整合RabbitMq ,用心看完这一篇就够了_小目标青年的博客-CSDN博客_springboot整合rabbitmq
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。