消息中间件学习六--SpringBoot集成RabbitMQ

1.介绍下RabbitMQ

   概述:消息队列

              实现AMQP(高级消息队列协议Advanced Message Queuing Protocol)的消息中间件的一种

 

  作用:主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用

  流程:

        一般消息队列都是生产者将消息发送到队列,消费者监听队列进行消费

       rabbitmq中一个虚拟主机(vhost默认 /)持有一个或者多个交换机(Exchange)。

       用户只能在虚拟主机的粒度进行权限控制,

       交换机根据一定的策略(RoutingKey)绑定(Binding)到队列(Queue)上,

       这样生产者和队列就没有直接联系,而是将消息发送的交换机,

       交换机再把消息转发到对应绑定的队列上

  交换机(Exchange)为rabbitmq独特的概念,用到的最常见的是4中类型:

 

1.Direct: 先匹配, 再投送。即在绑定时设定一个routing_key, 消息的routing_key匹配时, 
才会被交换器投送到绑定的队列中去. 交换机跟队列必须是精确的对应关系,这种最为简单。
2.Topic: 转发消息主要是根据通配符。在这种交换机下,队列和交换机的绑定会定义一种路由模式,
那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发消息 这种可以认为是Direct 的灵活版
3.Headers: 也是根据规则匹配, 相较于 direct 和 topic 固定地使用 routingkey ,
headers则是一个自定义匹配规则的类型, 在队列与交换器绑定时会设定一组键值对规则,
消息中也包括一组键值对( headers属性),当这些键值对有一对或全部匹配时,消息被投送到对应队列
4.Fanout : 消息广播模式,不管路由键或者是路由模式,
会把消息发给绑定给它的全部队列,如果配置了routingkey会被忽略

 

2.搭建

   第一步:配置依赖   

   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

  第二步:配置yml文件

 

spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: maxzhao
    password: maxzhao
    #支持发布确认
    publisher-confirms: true 
    #支持发布返回
    publisher-returns: true      
    # 默认 /
    virtual-host: maxzhao_vhost 
    listener:
      simple:
        acknowledge-mode: manual #采用手动应答
        concurrency: 1 #指定最小的消费者数量
        max-concurrency: 1 #指定最大的消费者数量
        retry:
          enabled: true #是否支持重试

 

第三步:不同的交换机(Exchange)的java实现

   案例:创建 2 个交换机directExchangefanoutExchange

               3个 队列 queueAqueueBqueueC

                队列directExchange作为定点发送,包含队列 A B

                队列fanoutExchange作为广播发送,包含队列 A B C

  配置不同的交互机: 
@Configuration
public class RabbitConfig {
    @Resource
    private RabbitTemplate rabbitTemplate;
    /**
     * 声明 Direct 交换机 支持持久化.
     *
     * @return the exchange
     */
    @Bean("directExchange")
    public Exchange directExchange() {
        return ExchangeBuilder.directExchange("DIRECT_EXCHANGE").durable(true).build();
    }
    /**
     * 声明 fanout 交换机.
     *
     * @return the exchange
     */
    @Bean("fanoutExchange")
    public FanoutExchange fanoutExchange() {
        return (FanoutExchange) ExchangeBuilder.fanoutExchange("FANOUT_EXCHANGE").durable(true).build();
    }
    /**
     * 声明一个队列 支持持久化.
     *
     * @return the queue
     */
    @Bean("queueA")
    public Queue directQueue() {
        return QueueBuilder.durable("QUEUE_A").build();
    }
    @Bean("queueB")
    public Queue directQueue() {
        return QueueBuilder.durable("QUEUE_B").build();
    }
    @Bean("queueC")
    public Queue directQueue() {
        return QueueBuilder.durable("QUEUE_C").build();
    }
    /**
     * 绑定队列A 到 direct 交换机.
     *
     * @param queue          the queue
     * @param exchange       the  exchange
     * @return the binding
     */
    @Bean
    public Binding bindingA(@Qualifier("queueA") Queue queue,
                            @Qualifier("directExchange") exchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange).with("DIRECT_ROUTING_KEY_A").noargs();
    }
    @Bean
    public Binding bindingA(@Qualifier("queueB") Queue queue,
                            @Qualifier("directExchange") exchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange).with("DIRECT_ROUTING_KEY_B").noargs();
    }
    /**
     * 绑定队列A 到 fanout 交换机.
     *
     * @param queue          the queue
     * @param exchange       the  exchange
     * @return the binding
     */
    @Bean
    public Binding bindingA(@Qualifier("queueA") Queue queue,
                            @Qualifier("fanoutExchange") exchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange);
    }
    @Bean
    public Binding bindingA(@Qualifier("queueB") Queue queue,
                            @Qualifier("fanoutExchange") exchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange).;
    }
    @Bean
    public Binding bindingA(@Qualifier("queueC") Queue queue,
                            @Qualifier("fanoutExchange") exchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange).;
    }

}

消息发送类

@Service
public class SenderService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 测试广播模式.
     *
     * @param p the p
     * @return the response entity
     */
    public void broadcast(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "", p, correlationData);
    }

    /**
     * 测试 Direct 模式.
     *
     * @param p the p
     * @return the response entity
     */
    public void directA(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_A", p, correlationData);
    }
    public void directB(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_B", p, correlationData);
    }
    public void directNull(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "", p, correlationData);
    }

}

消息接收类

@Component
public class Receiver {
    private static final Logger log = LoggerFactory.getLogger(Receiver.class);

    /**
     * FANOUT广播队列监听一.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"QUEUE_A"})
    public void on(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        log.debug("FANOUT_QUEUE_A " + new String(message.getBody()));
    }
    @RabbitListener(queues = {"QUEUE_B"})
    public void t(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        log.debug("FANOUT_QUEUE_B " + new String(message.getBody()));
    }
    @RabbitListener(queues = {"QUEUE_C"})
    public void t(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        log.debug("FANOUT_QUEUE_C " + new String(message.getBody()));
    }

    /**
     * DIRECT模式.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"DIRECT_QUEUE"})
    public void message(Message message, Channel channel) throws IOException {
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        log.debug("DIRECT_QUEUE " + new String(message.getBody()));
    }
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SenderServiceTest {
    @Autowired
    private SenderService senderService;

    @Test
    public void testCache() throws InterruptedException {
        // 测试广播模式
        senderService.broadcast("   Test    同学们集合啦!");
        // 测试Direct模式
        senderService.directA("   Test    定点消息 A ");
        senderService.directB("   Test    定点消息 B ");
        senderService.directNull("   Test    定点消息 null key ");
        Thread.sleep(5000L);
    }
}

 

 

官网:https://www.rabbitmq.com/getstarted.html

 

 学习来源:https://www.jianshu.com/p/378aef58b58e

 

posted @ 2020-09-22 15:35  小窝蜗  阅读(179)  评论(0编辑  收藏  举报