springboot集成rabbitMq

0.前言

发现md代码内部不换行的排版问题(复制的代码),是md的缺陷一直没改,在这样下去要放弃md了使用其他编辑器,很影响阅读,所以这篇博客暂时用默认编辑器。

1.新建工程,添加依赖

 
compile('org.springframework.boot:spring-boot-starter-amqp')
 

2.配置application.yml

 
#配置服务端
spring:
  application:
      name: rabbit-test
  rabbitmq:
    host: 10.2.6.33
    port: 5672
    username: gaojinliang
    password: 【自己对应的密码】 

3.RabbitMq的基本概念

 
内部实际上也是AMQP中的基本概念,AMQP中增加了Exchange和Binding的角色。生产者把消息发布到Exchange上,消息最终到达队列并被消费者接收,而
Binding决定交换器的消息应该发送到哪个队列。
 
Exchange 类型
    Exchange分发消息的时候根据类型的不同分发策略有区别,目前有四种类型,direct、fanout、topic、headers 。headers 匹配 AMQP 消息的 header
 而不是路由键,此外 headers 交换器和 direct 交换器完全一致,但性能差很多,目前几乎用不到了,所以直接看另外三种类型:
 

3.1direct

    消息中的路由键(routing key)如果和Binding中的binding key一致,交换器就将消息发到对应的队列中。路由键与队列名完全匹配,如果一个队列绑定到交换机要求路由键为“dog”,则只转发routing key标记为“dog”的消息,不会转发“dog.puppy”,也不会转发“dog.guard”等等。他是完全匹配,单播的模式。
以下是direct的场景,也是最简单,最常用的模式。
 
MQ配置
@Configuration
public class RabbitQueueConfig {
 
    @Bean
    public Queue queue1() {
        return new Queue("queue1", true); //持久化
    }
 
 
发送者
  @Autowired
  private AmqpTemplate rabbitTemplate;
 
  @GetMapping("/queue")
  public String sendQueueMsg(@RequestParam("msg") String msg) {
    rabbitTemplate.convertAndSend("queue1", msg);
      return "success";
  } 
接收者
@Component
public class QueueReceiver {
 
 @RabbitListener(queues = "queue1")
 @RabbitHandler
    public void process(String strs) {
        System.out.println("接收到:" + strs);
    }
 
 

3.2fanout

    每个发到fanout类型交换器的消息都会分到所有绑定的队列上。fanout交换器不处理路由键,只是简单的将队列绑定到交换器上,每个发送到交换器的消息都会被
转发到与该交换器绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。fanout类型转发消息是最快的。
 
以下是fanout场景,单个微服务集群的情况下每个节点都绑定到一个direct交换机上 (例子中是服务端口区分队列,也可以是别的key),然后每个节点都能收到
消息做一些配置更新等操作。
 
MQ配置
@Configuration
public class RabbitFanoutConfig {
 
    @Value("${server.port}")
    private String port;
 
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange ("fanoutExchange");
    }
    
    @Bean
    public Queue fanoutTp() {
        return new Queue("fanout.tp."+port);
    }    
    
    @Bean
    public Binding fanoutBinding() {
        return BindingBuilder.bind(fanoutTp()).to(fanoutExchange());
    }
 
}
 
发送者
@GetMapping("/fanout")
 public String sendFanoutMsg(@RequestParam("msg") String msg) {
 rabbitTemplate.convertAndSend("fanoutExchange","", msg);
 return "success";
 } 
 
接收者
@Component
public class FanoutRecerver {
 
 @RabbitListener(queues = "fanout.tp.${server.port}")
 @RabbitHandler
    public void process(String strs) {
        System.out.println("fanout.tp接收到:" + strs);
    }
 
 

3.3topic

    topic交换器通过模式匹配分配消息的路由键属性,将路由键和单个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定建的字符串切分成单词,这些单词
之间用点隔开。他同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配不多不少一个单词。
以下是topic场景,单个微服务接收到同一个消息后多个功能协调工作,也适用按分类更新、同一问题需要特定人员知晓等场景
 
MQ配置:
@Configuration
public class RabbitTopicConfig {
 
    @Bean
    public TopicExchange topicExchange() {
        return new TopicExchange ("topicExchange");
    }
    
    @Bean
    public Queue topicTp1() {
        return new Queue("topic.tp2.one");
    }
    
    @Bean
    public Queue topicTp2() {
        return new Queue("topic.tp2.two");
    }
    
    @Bean
    public Binding binding1() {
        return BindingBuilder.bind(topicTp1()).to(topicExchange()).with("topic.tp2.*"); //* 后面匹配单个key
    }
    
    @Bean
    public Binding binding2() {
        return BindingBuilder.bind(topicTp2()).to(topicExchange()).with("topic.tp2.#"); //# 后面匹配多个key
    }
 
 
发送者
@GetMapping("/topic")
 public String sendTopicMsg(@RequestParam("msg") String msg) {
   rabbitTemplate.convertAndSend("topicExchange","topic.tp2.all", msg);
   return "success";
 } 
 
接收者
@Component
public class TopicRecerver {
 
 @RabbitListener(queues = "topic.tp2.one")
 @RabbitHandler
    public void process(String strs) {
        System.out.println("topic.tp2.one 接收到:" + strs);
    }
 
 @RabbitListener(queues = "topic.tp2.two")
 @RabbitHandler
    public void process2(String strs) {
        System.out.println("topic.tp2.two 接收到:" + strs);
    }
 
}
 

4.接收端手动确认

    上面提到的内容都是消息自动确认,当我们程序中收到消息处理失败需要MQ重发时就需要用到手动确认。
application.yml 配置  spring.rabbitmq.listener.simple.acknowledge-mode=MANUAL
spring:
  application:
      name: rabbit-test
  rabbitmq:
    host: 10.2.6.33
    port: 5672
    username: liuyanhui
    password: liuyanhui
    listener:
      simple:
        acknowledge-mode: MANUAL 
 
在监听一端
@Component
public class QueueReceiver {
 
 @RabbitListener(queues = "queue2")
 @RabbitHandler
    public void process(String strs, Message message, Channel channel) throws IOException {
        System.out.println("接收到:" + strs);
        
        //channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //确认成功
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true); //确认失败
    }
 
 
 
channel.basicAck 确认成功
 
channel.basicNack  确认失败 : 最后一个参数代表是否需要重发,需要根据实际执行情况做选择,否则可能陷入死循环。
posted @ 2019-12-25 16:15  jnnleo  阅读(351)  评论(0编辑  收藏  举报