手把手教你 springBoot 整合 rabbitMQ,利用 MQ 实现事务补偿

开发 前端
rabbitMQ 在互联网公司有着大规模应用,本篇将实战介绍 springboot 整合 rabbitMQ,同时也将在具体的业务场景中介绍利用 MQ 实现事务补偿操作。

[[341134]]

本文转载自微信公众号「Java极客技术」,作者鸭血粉丝。转载本文请联系Java极客技术公众号。  

rabbitMQ 在互联网公司有着大规模应用,本篇将实战介绍 springboot 整合 rabbitMQ,同时也将在具体的业务场景中介绍利用 MQ 实现事务补偿操作。

一、介绍

本篇我们一起来实操一下SpringBoot整合rabbitMQ,为后续业务处理做铺垫。

废话不多说,直奔主题!

二、整合实战

2.1、创建一个 maven 工程,引入 amqp 包

  1. <!--amqp 支持--> 
  2. <dependency> 
  3.     <groupId>org.springframework.boot</groupId> 
  4.     <artifactId>spring-boot-starter-amqp</artifactId> 
  5. </dependency> 

2.2、在全局文件中配置 rabbitMQ 服务信息

  1. spring.rabbitmq.addresses=197.168.24.206:5672 
  2. spring.rabbitmq.username=guest 
  3. spring.rabbitmq.password=guest 
  4. spring.rabbitmq.virtual-host=/ 

其中,spring.rabbitmq.addresses参数值为 rabbitmq 服务器地址

2.3、编写 rabbitmq 配置类

  1. @Slf4j 
  2. @Configuration 
  3. public class RabbitConfig { 
  4.  
  5.     /** 
  6.      * 初始化连接工厂 
  7.      * @param addresses 
  8.      * @param userName 
  9.      * @param password 
  10.      * @param vhost 
  11.      * @return 
  12.      */ 
  13.     @Bean 
  14.     ConnectionFactory connectionFactory(@Value("${spring.rabbitmq.addresses}") String addresses, 
  15.                                         @Value("${spring.rabbitmq.username}") String userName, 
  16.                                         @Value("${spring.rabbitmq.password}") String password
  17.                                         @Value("${spring.rabbitmq.virtual-host}") String vhost) { 
  18.         CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); 
  19.         connectionFactory.setAddresses(addresses); 
  20.         connectionFactory.setUsername(userName); 
  21.         connectionFactory.setPassword(password); 
  22.         connectionFactory.setVirtualHost(vhost); 
  23.         return connectionFactory; 
  24.     } 
  25.  
  26.     /** 
  27.      * 重新实例化 RabbitAdmin 操作类 
  28.      * @param connectionFactory 
  29.      * @return 
  30.      */ 
  31.     @Bean 
  32.     public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){ 
  33.         return new RabbitAdmin(connectionFactory); 
  34.     } 
  35.  
  36.     /** 
  37.      * 重新实例化 RabbitTemplate 操作类 
  38.      * @param connectionFactory 
  39.      * @return 
  40.      */ 
  41.     @Bean 
  42.     public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){ 
  43.         RabbitTemplate rabbitTemplate=new RabbitTemplate(connectionFactory); 
  44.         //数据转换为json存入消息队列 
  45.         rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter()); 
  46.         return rabbitTemplate; 
  47.     } 
  48.  
  49.     /** 
  50.      * 将 RabbitUtil 操作工具类加入IOC容器 
  51.      * @return 
  52.      */ 
  53.     @Bean 
  54.     public RabbitUtil rabbitUtil(){ 
  55.         return new RabbitUtil(); 
  56.     } 
  57.  

2.4、编写 RabbitUtil 工具类

  1. public class RabbitUtil { 
  2.  
  3.     private static final Logger logger = LoggerFactory.getLogger(RabbitUtil.class); 
  4.  
  5.     @Autowired 
  6.     private RabbitAdmin rabbitAdmin; 
  7.  
  8.     @Autowired 
  9.     private RabbitTemplate rabbitTemplate; 
  10.  
  11.     /** 
  12.      * 创建Exchange 
  13.      * @param exchangeName 
  14.      */ 
  15.     public void addExchange(String exchangeType, String exchangeName){ 
  16.         Exchange exchange = createExchange(exchangeType, exchangeName); 
  17.         rabbitAdmin.declareExchange(exchange); 
  18.     } 
  19.  
  20.     /** 
  21.      * 删除一个Exchange 
  22.      * @param exchangeName 
  23.      */ 
  24.     public boolean deleteExchange(String exchangeName){ 
  25.         return rabbitAdmin.deleteExchange(exchangeName); 
  26.     } 
  27.  
  28.     /** 
  29.      * 创建一个指定的Queue 
  30.      * @param queueName 
  31.      * @return queueName 
  32.      */ 
  33.     public void addQueue(String queueName){ 
  34.         Queue queue = createQueue(queueName); 
  35.         rabbitAdmin.declareQueue(queue); 
  36.     } 
  37.  
  38.     /** 
  39.      * 删除一个queue 
  40.      * @return queueName 
  41.      * @param queueName 
  42.      */ 
  43.     public boolean deleteQueue(String queueName){ 
  44.         return rabbitAdmin.deleteQueue(queueName); 
  45.     } 
  46.  
  47.     /** 
  48.      * 按照筛选条件,删除队列 
  49.      * @param queueName 
  50.      * @param unused 是否被使用 
  51.      * @param empty 内容是否为空 
  52.      */ 
  53.     public void deleteQueue(String queueName, boolean unused, boolean empty){ 
  54.         rabbitAdmin.deleteQueue(queueName,unused,empty); 
  55.     } 
  56.  
  57.     /** 
  58.      * 清空某个队列中的消息,注意,清空的消息并没有被消费 
  59.      * @return queueName 
  60.      * @param queueName 
  61.      */ 
  62.     public void purgeQueue(String queueName){ 
  63.         rabbitAdmin.purgeQueue(queueName, false); 
  64.     } 
  65.  
  66.     /** 
  67.      * 判断指定的队列是否存在 
  68.      * @param queueName 
  69.      * @return 
  70.      */ 
  71.     public boolean existQueue(String queueName){ 
  72.         return rabbitAdmin.getQueueProperties(queueName) == null ? false : true
  73.     } 
  74.  
  75.     /** 
  76.      * 绑定一个队列到一个匹配型交换器使用一个routingKey 
  77.      * @param exchangeType 
  78.      * @param exchangeName 
  79.      * @param queueName 
  80.      * @param routingKey 
  81.      * @param isWhereAll 
  82.      * @param headers EADERS模式类型设置,其他模式类型传空 
  83.      */ 
  84.     public void addBinding(String exchangeType, String exchangeName, String queueName, String routingKey, boolean isWhereAll, Map<String, Object> headers){ 
  85.         Binding binding = bindingBuilder(exchangeType, exchangeName, queueName, routingKey, isWhereAll, headers); 
  86.         rabbitAdmin.declareBinding(binding); 
  87.     } 
  88.  
  89.     /** 
  90.      * 声明绑定 
  91.      * @param binding 
  92.      */ 
  93.     public void addBinding(Binding binding){ 
  94.         rabbitAdmin.declareBinding(binding); 
  95.     } 
  96.  
  97.     /** 
  98.      * 解除交换器与队列的绑定 
  99.      * @param exchangeType 
  100.      * @param exchangeName 
  101.      * @param queueName 
  102.      * @param routingKey 
  103.      * @param isWhereAll 
  104.      * @param headers 
  105.      */ 
  106.     public void removeBinding(String exchangeType, String exchangeName, String queueName, String routingKey, boolean isWhereAll, Map<String, Object> headers){ 
  107.         Binding binding = bindingBuilder(exchangeType, exchangeName, queueName, routingKey, isWhereAll, headers); 
  108.         removeBinding(binding); 
  109.     } 
  110.  
  111.     /** 
  112.      * 解除交换器与队列的绑定 
  113.      * @param binding 
  114.      */ 
  115.     public void removeBinding(Binding binding){ 
  116.         rabbitAdmin.removeBinding(binding); 
  117.     } 
  118.  
  119.     /** 
  120.      * 创建一个交换器、队列,并绑定队列 
  121.      * @param exchangeType 
  122.      * @param exchangeName 
  123.      * @param queueName 
  124.      * @param routingKey 
  125.      * @param isWhereAll 
  126.      * @param headers 
  127.      */ 
  128.     public void andExchangeBindingQueue(String exchangeType, String exchangeName, String queueName, String routingKey, boolean isWhereAll, Map<String, Object> headers){ 
  129.         //声明交换器 
  130.         addExchange(exchangeType, exchangeName); 
  131.         //声明队列 
  132.         addQueue(queueName); 
  133.         //声明绑定关系 
  134.         addBinding(exchangeType, exchangeName, queueName, routingKey, isWhereAll, headers); 
  135.     } 
  136.  
  137.     /** 
  138.      * 发送消息 
  139.      * @param exchange 
  140.      * @param routingKey 
  141.      * @param object 
  142.      */ 
  143.     public void convertAndSend(String exchange, String routingKey, final Object object){ 
  144.         rabbitTemplate.convertAndSend(exchange, routingKey, object); 
  145.     } 
  146.  
  147.     /** 
  148.      * 转换Message对象 
  149.      * @param messageType 
  150.      * @param msg 
  151.      * @return 
  152.      */ 
  153.     public Message getMessage(String messageType, Object msg){ 
  154.         MessageProperties messageProperties = new MessageProperties(); 
  155.         messageProperties.setContentType(messageType); 
  156.         Message message = new Message(msg.toString().getBytes(),messageProperties); 
  157.         return message; 
  158.     } 
  159.  
  160.     /** 
  161.      * 声明交换机 
  162.      * @param exchangeType 
  163.      * @param exchangeName 
  164.      * @return 
  165.      */ 
  166.     private Exchange createExchange(String exchangeType, String exchangeName){ 
  167.         if(ExchangeType.DIRECT.equals(exchangeType)){ 
  168.             return new DirectExchange(exchangeName); 
  169.         } 
  170.         if(ExchangeType.TOPIC.equals(exchangeType)){ 
  171.             return new TopicExchange(exchangeName); 
  172.         } 
  173.         if(ExchangeType.HEADERS.equals(exchangeType)){ 
  174.             return new HeadersExchange(exchangeName); 
  175.         } 
  176.         if(ExchangeType.FANOUT.equals(exchangeType)){ 
  177.             return new FanoutExchange(exchangeName); 
  178.         } 
  179.         return null
  180.     } 
  181.  
  182.     /** 
  183.      * 声明绑定关系 
  184.      * @param exchangeType 
  185.      * @param exchangeName 
  186.      * @param queueName 
  187.      * @param routingKey 
  188.      * @param isWhereAll 
  189.      * @param headers 
  190.      * @return 
  191.      */ 
  192.     private Binding bindingBuilder(String exchangeType, String exchangeName, String queueName, String routingKey, boolean isWhereAll, Map<String, Object> headers){ 
  193.         if(ExchangeType.DIRECT.equals(exchangeType)){ 
  194.             return BindingBuilder.bind(new Queue(queueName)).to(new DirectExchange(exchangeName)).with(routingKey); 
  195.         } 
  196.         if(ExchangeType.TOPIC.equals(exchangeType)){ 
  197.             return BindingBuilder.bind(new Queue(queueName)).to(new TopicExchange(exchangeName)).with(routingKey); 
  198.         } 
  199.         if(ExchangeType.HEADERS.equals(exchangeType)){ 
  200.             if(isWhereAll){ 
  201.                 return BindingBuilder.bind(new Queue(queueName)).to(new HeadersExchange(exchangeName)).whereAll(headers).match(); 
  202.             }else
  203.                 return BindingBuilder.bind(new Queue(queueName)).to(new HeadersExchange(exchangeName)).whereAny(headers).match(); 
  204.             } 
  205.         } 
  206.         if(ExchangeType.FANOUT.equals(exchangeType)){ 
  207.             return BindingBuilder.bind(new Queue(queueName)).to(new FanoutExchange(exchangeName)); 
  208.         } 
  209.         return null
  210.     } 
  211.  
  212.     /** 
  213.      * 声明队列 
  214.      * @param queueName 
  215.      * @return 
  216.      */ 
  217.     private Queue createQueue(String queueName){ 
  218.         return new Queue(queueName); 
  219.     } 
  220.  
  221.  
  222.     /** 
  223.      * 交换器类型 
  224.      */ 
  225.     public final static class ExchangeType { 
  226.  
  227.         /** 
  228.          * 直连交换机(全文匹配) 
  229.          */ 
  230.         public final static String DIRECT = "DIRECT"
  231.  
  232.         /** 
  233.          * 通配符交换机(两种通配符:*只能匹配一个单词,#可以匹配零个或多个) 
  234.          */ 
  235.         public final static String TOPIC = "TOPIC"
  236.  
  237.         /** 
  238.          * 头交换机(自定义键值对匹配,根据发送消息内容中的headers属性进行匹配) 
  239.          */ 
  240.         public final static String HEADERS = "HEADERS"
  241.  
  242.         /** 
  243.          * 扇形(广播)交换机 (将消息转发到所有与该交互机绑定的队列上) 
  244.          */ 
  245.         public final static String FANOUT = "FANOUT"
  246.     } 

此致, rabbitMQ 核心操作功能操作已经开发完毕!

2.5、编写队列监听类(静态)

  1. @Slf4j 
  2. @Configuration 
  3. public class DirectConsumeListener { 
  4.  
  5.     /** 
  6.      * 监听指定队列,名称:mq.direct.1 
  7.      * @param message 
  8.      * @param channel 
  9.      * @throws IOException 
  10.      */ 
  11.     @RabbitListener(queues = "mq.direct.1"
  12.     public void consume(Message message, Channel channel) throws IOException { 
  13.         log.info("DirectConsumeListener,收到消息: {}", message.toString()); 
  14.     } 

如果你需要监听指定的队列,只需要方法上加上@RabbitListener(queues = "")即可,同时填写对应的队列名称。

但是,如果你想动态监听队列,而不是通过写死在方法上呢?

请看下面介绍!

2.6、编写队列监听类(动态)

重新实例化一个SimpleMessageListenerContainer对象,这个对象就是监听容器。

  1. @Slf4j 
  2. @Configuration 
  3. public class DynamicConsumeListener { 
  4.  
  5.     /** 
  6.      * 使用SimpleMessageListenerContainer实现动态监听 
  7.      * @param connectionFactory 
  8.      * @return 
  9.      */ 
  10.     @Bean 
  11.     public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory){ 
  12.         SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory); 
  13.         container.setMessageListener((MessageListener) message -> { 
  14.             log.info("ConsumerMessageListen,收到消息: {}", message.toString()); 
  15.         }); 
  16.         return container; 
  17.     } 

如果想向SimpleMessageListenerContainer添加监听队列或者移除队列,只需通过如下方式即可操作。

  1. @Slf4j 
  2. @RestController 
  3. @RequestMapping("/consumer"
  4. public class ConsumerController { 
  5.  
  6.     @Autowired 
  7.     private SimpleMessageListenerContainer container; 
  8.  
  9.     @Autowired 
  10.     private RabbitUtil rabbitUtil; 
  11.  
  12.     /** 
  13.      * 添加队列到监听器 
  14.      * @param consumerInfo 
  15.      */ 
  16.     @PostMapping("addQueue"
  17.     public void addQueue(@RequestBody ConsumerInfo consumerInfo) { 
  18.         boolean existQueue = rabbitUtil.existQueue(consumerInfo.getQueueName()); 
  19.         if(!existQueue){ 
  20.             throw new CommonExecption("当前队列不存在"); 
  21.         } 
  22.         //消费mq消息的类 
  23.         container.addQueueNames(consumerInfo.getQueueName()); 
  24.         //打印监听容器中正在监听到队列 
  25.         log.info("container-queue:{}", JsonUtils.toJson(container.getQueueNames())); 
  26.     } 
  27.  
  28.     /** 
  29.      * 移除正在监听的队列 
  30.      * @param consumerInfo 
  31.      */ 
  32.     @PostMapping("removeQueue"
  33.     public void removeQueue(@RequestBody ConsumerInfo consumerInfo) { 
  34.         //消费mq消息的类 
  35.         container.removeQueueNames(consumerInfo.getQueueName()); 
  36.         //打印监听容器中正在监听到队列 
  37.         log.info("container-queue:{}", JsonUtils.toJson(container.getQueueNames())); 
  38.     } 
  39.  
  40.     /** 
  41.      * 查询监听容器中正在监听到队列 
  42.      */ 
  43.     @PostMapping("queryListenerQueue"
  44.     public void queryListenerQueue() { 
  45.         log.info("container-queue:{}", JsonUtils.toJson(container.getQueueNames())); 
  46.     } 

2.7、发送消息到交换器

发送消息到交换器,非常简单,只需要通过如下方式即可!

  • 先编写一个请求参数实体类
  1. @Data 
  2. public class ProduceInfo implements Serializable { 
  3.  
  4.     private static final long serialVersionUID = 1l; 
  5.  
  6.     /** 
  7.      * 交换器名称 
  8.      */ 
  9.     private String exchangeName; 
  10.  
  11.     /** 
  12.      * 路由键key 
  13.      */ 
  14.     private String routingKey; 
  15.  
  16.     /** 
  17.      * 消息内容 
  18.      */ 
  19.     public String msg; 
  • 编写接口api
  1. @RestController 
  2. @RequestMapping("/produce"
  3. public class ProduceController { 
  4.  
  5.     @Autowired 
  6.     private RabbitUtil rabbitUtil; 
  7.  
  8.     /** 
  9.      * 发送消息到交换器 
  10.      * @param produceInfo 
  11.      */ 
  12.     @PostMapping("sendMessage"
  13.     public void sendMessage(@RequestBody ProduceInfo produceInfo) { 
  14.         rabbitUtil.convertAndSend(produceInfo.getExchangeName(), produceInfo.getRoutingKey(), produceInfo); 
  15.     } 
  16.  

当然,你也可以直接使用rabbitTemplate操作类,来实现发送消息。

  1. rabbitTemplate.convertAndSend(exchange, routingKey, message); 

参数内容解释:

  • exchange:表示交换器名称
  • routingKey:表示路由键key
  • message:表示消息

2.8、交换器、队列维护操作

如果想通过接口对 rabbitMQ 中的交换器、队列以及绑定关系进行维护,通过如下方式接口操作,即可实现!

先编写一个请求参数实体类

  1. @Data 
  2. public class QueueConfig implements Serializable
  3.  
  4.     private static final long serialVersionUID = 1l; 
  5.  
  6.     /** 
  7.      * 交换器类型 
  8.      */ 
  9.     private String exchangeType; 
  10.  
  11.     /** 
  12.      * 交换器名称 
  13.      */ 
  14.     private String exchangeName; 
  15.  
  16.     /** 
  17.      * 队列名称 
  18.      */ 
  19.     private String queueName; 
  20.  
  21.     /** 
  22.      * 路由键key 
  23.      */ 
  24.     private String routingKey; 

编写接口api

  1. /** 
  2.  * rabbitMQ管理操作控制层 
  3.  */ 
  4. @RestController 
  5. @RequestMapping("/config"
  6. public class RabbitController { 
  7.  
  8.  
  9.     @Autowired 
  10.     private RabbitUtil rabbitUtil; 
  11.  
  12.     /** 
  13.      * 创建交换器 
  14.      * @param config 
  15.      */ 
  16.     @PostMapping("addExchange"
  17.     public void addExchange(@RequestBody QueueConfig config) { 
  18.         rabbitUtil.addExchange(config.getExchangeType(), config.getExchangeName()); 
  19.     } 
  20.  
  21.     /** 
  22.      * 删除交换器 
  23.      * @param config 
  24.      */ 
  25.     @PostMapping("deleteExchange"
  26.     public void deleteExchange(@RequestBody QueueConfig config) { 
  27.         rabbitUtil.deleteExchange(config.getExchangeName()); 
  28.     } 
  29.  
  30.     /** 
  31.      * 添加队列 
  32.      * @param config 
  33.      */ 
  34.     @PostMapping("addQueue"
  35.     public void addQueue(@RequestBody QueueConfig config) { 
  36.         rabbitUtil.addQueue(config.getQueueName()); 
  37.     } 
  38.  
  39.     /** 
  40.      * 删除队列 
  41.      * @param config 
  42.      */ 
  43.     @PostMapping("deleteQueue"
  44.     public void deleteQueue(@RequestBody QueueConfig config) { 
  45.         rabbitUtil.deleteQueue(config.getQueueName()); 
  46.     } 
  47.  
  48.     /** 
  49.      * 清空队列数据 
  50.      * @param config 
  51.      */ 
  52.     @PostMapping("purgeQueue"
  53.     public void purgeQueue(@RequestBody QueueConfig config) { 
  54.         rabbitUtil.purgeQueue(config.getQueueName()); 
  55.     } 
  56.  
  57.     /** 
  58.      * 添加绑定 
  59.      * @param config 
  60.      */ 
  61.     @PostMapping("addBinding"
  62.     public void addBinding(@RequestBody QueueConfig config) { 
  63.         rabbitUtil.addBinding(config.getExchangeType(), config.getExchangeName(), config.getQueueName(), config.getRoutingKey(), falsenull); 
  64.     } 
  65.  
  66.     /** 
  67.      * 解除绑定 
  68.      * @param config 
  69.      */ 
  70.     @PostMapping("removeBinding"
  71.     public void removeBinding(@RequestBody QueueConfig config) { 
  72.         rabbitUtil.removeBinding(config.getExchangeType(), config.getExchangeName(), config.getQueueName(), config.getRoutingKey(), falsenull); 
  73.     } 
  74.  
  75.     /** 
  76.      * 创建头部类型的交换器 
  77.      * 判断条件是所有的键值对都匹配成功才发送到队列 
  78.      * @param config 
  79.      */ 
  80.     @PostMapping("andExchangeBindingQueueOfHeaderAll"
  81.     public void andExchangeBindingQueueOfHeaderAll(@RequestBody QueueConfig config) { 
  82.         HashMap<String, Object> header = new HashMap<>(); 
  83.         header.put("queue""queue"); 
  84.         header.put("bindType""whereAll"); 
  85.         rabbitUtil.andExchangeBindingQueue(RabbitUtil.ExchangeType.HEADERS, config.getExchangeName(), config.getQueueName(), nulltrue, header); 
  86.     } 
  87.  
  88.     /** 
  89.      * 创建头部类型的交换器 
  90.      * 判断条件是只要有一个键值对匹配成功就发送到队列 
  91.      * @param config 
  92.      */ 
  93.     @PostMapping("andExchangeBindingQueueOfHeaderAny"
  94.     public void andExchangeBindingQueueOfHeaderAny(@RequestBody QueueConfig config) { 
  95.         HashMap<String, Object> header = new HashMap<>(); 
  96.         header.put("queue""queue"); 
  97.         header.put("bindType""whereAny"); 
  98.         rabbitUtil.andExchangeBindingQueue(RabbitUtil.ExchangeType.HEADERS, config.getExchangeName(), config.getQueueName(), nullfalse, header); 
  99.     } 

至此,rabbitMQ 管理器基本的 crud 全部开发完成!

三、利用 MQ 实现事务补偿

当然,我们花了这么大的力气,绝不仅仅是为了将 rabbitMQ 通过 web 项目将其管理起来,最重要的是能投入业务使用中去!

上面的操作只是告诉我们怎么使用 rabbitMQ!

  • 当你仔细回想整个过程的时候,其实还是回到最初那个问题,什么时候使用 MQ ?

以常见的订单系统为例,用户点击【下单】按钮之后的业务逻辑可能包括:支付订单、扣减库存、生成相应单据、发红包、发短信通知等等。

在业务发展初期这些逻辑可能放在一起同步执行,随着业务的发展订单量增长,需要提升系统服务的性能,这时可以将一些不需要立即生效的操作拆分出来异步执行,比如发放红包、发短信通知等。这种场景下就可以用 MQ ,在下单的主流程(比如扣减库存、生成相应单据)完成之后发送一条消息到 MQ 让主流程快速完结,而由另外的单独线程拉取 MQ 的消息(或者由 MQ 推送消息),当发现 MQ 中有发红包或发短信之类的消息时,执行相应的业务逻辑。

这种是利用 MQ 实现业务解耦,其它的场景包括最终一致性、广播、错峰流控等等。

利用 MQ 实现业务解耦的过程其实也很简单。

  • 当主流程结束之后,将消息推送到发红包、发短信交换器中即可
  1. @Service 
  2. public class OrderService { 
  3.  
  4.     @Autowired 
  5.     private RabbitUtil rabbitUtil; 
  6.  
  7.     /** 
  8.      * 创建订单 
  9.      * @param order 
  10.      */ 
  11.     @Transactional 
  12.     public void createOrder(Order order){ 
  13.         //1、创建订单 
  14.         //2、调用库存接口,减库存 
  15.         //3、向客户发放红包 
  16.         rabbitUtil.convertAndSend("exchange.send.bonus"nullorder); 
  17.         //4、发短信通知 
  18.         rabbitUtil.convertAndSend("exchange.sms.message"nullorder); 
  19.     } 
  20.  
  • 监听发红包操作
  1. /** 
  2.  * 监听发红包 
  3.  * @param message 
  4.  * @param channel 
  5.  * @throws IOException 
  6.  */ 
  7. @RabbitListener(queues = "exchange.send.bonus"
  8. public void consume(Message message, Channel channel) throws IOException { 
  9.     String msgJson = new String(message.getBody(),"UTF-8"); 
  10.     log.info("收到消息: {}", message.toString()); 
  11.  
  12.     //调用发红包接口 

监听发短信操作

  1. /** 
  2.  * 监听发短信 
  3.  * @param message 
  4.  * @param channel 
  5.  * @throws IOException 
  6.  */ 
  7. @RabbitListener(queues = "exchange.sms.message"
  8. public void consume(Message message, Channel channel) throws IOException { 
  9.     String msgJson = new String(message.getBody(),"UTF-8"); 
  10.     log.info("收到消息: {}", message.toString()); 
  11.  
  12.     //调用发短信接口 

既然 MQ 这么好用,那是不是完全可以将以前的业务也按照整个模型进行拆分呢?

答案显然不是!

当引入 MQ 之后业务的确是解耦了,但是当 MQ 一旦挂了,所有的服务基本都挂了,是不是很可怕!

但是没关系,俗话说,兵来将挡、水来土掩,这句话同样适用于 IT 开发者,有坑填坑!

在下篇文章中,我们会详细介绍 rabbitMQ 的集群搭建和部署,保证消息几乎 100% 的投递和消费。

四、总结

本篇主要围绕SpringBoot整合rabbitMQ做内容介绍,可能也有理解不到位的地方,欢迎网友批评指出!

 

责任编辑:武晓燕 来源: Java极客技术
相关推荐

2023-04-26 12:46:43

DockerSpringKubernetes

2009-11-09 14:57:37

WCF上传文件

2011-01-06 10:39:25

.NET程序打包

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印机

2022-08-04 10:39:23

Jenkins集成CD

2021-03-12 10:01:24

JavaScript 前端表单验证

2020-05-15 08:07:33

JWT登录单点

2021-07-14 09:00:00

JavaFX开发应用

2011-04-21 10:32:44

MySQL双机同步

2021-02-26 11:54:38

MyBatis 插件接口

2011-02-22 13:46:27

微软SQL.NET

2021-12-28 08:38:26

Linux 中断唤醒系统Linux 系统

2011-10-06 14:32:43

2020-04-08 09:09:37

VS Code编码编辑器

2022-03-14 14:47:21

HarmonyOS操作系统鸿蒙

2022-01-08 20:04:20

拦截系统调用

2022-07-27 08:16:22

搜索引擎Lucene

2022-12-07 08:42:35

2016-05-12 11:54:39

点赞
收藏

51CTO技术栈公众号