RabbitMq详解(二、项目集成)| 8月更文挑战

250 阅读5分钟

这是我参与8月更文挑战的第22天

SpringBoot集成RabbitMq

三个注解:

@EnableRabbit:

@EnableRabbit和@Configuration一起使用,可以加在类或者方法上,这个注解开启了容器对注册的bean的@RabbitListener检查。

@RabbitHandler:

@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理,具体使用哪个方法处理,根据 MessageConverter 转换后的参数类型

@RabbitListener:

注解来指定某方法作为消息消费的方法,例如监听某 Queue 里面的消息

springboot定义直连交换机

1、jar包

image.png

2、配置文件(消费者同理)

image.png

生产者配置信息
@Bean
    public Queue DirectQueue(){

        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue(QUEUE_DIRECT_NAME,true);
    }
    @Bean
    public Queue DirectQueue1(){

        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue(QUEUE_DIRECT_NAME1,true);
    }

    //声明交换机
    /**
     * CustomExchange
     * DirectExchange :直连型(routing)交换机
     * FanoutExchange :广播(订阅)交换机
     * HeadersExchange :hdeader交换机
     * TopicExchange.class :通配符交换机
     *
     * String name, 交换机名称
     * boolean durable,是否持久化
     * boolean autoDelete,是否自动删除
     * Map<String, Object> arguments 拓展参数
     */
    @Bean
    public DirectExchange getDirectExchange(){
        return new DirectExchange(EXCHANGE_DIRECT_NAME,true,false,null);
    }
    @Bean
    //将队列绑定至交换机
    public Binding getBindingDirect(){
        return BindingBuilder.bind(DirectQueue()).to(getDirectExchange()).with(ROUTING_KEY_DIRECT_NAME);
    }

生产者发送消息通过 参数:String exchange, 交换机名称 * String routingKey, routingkey * Object object,消息 * @Nullable CorrelationData correlationData RabbitTemplate.convertAndSend()

消费者

image.png

解决mq发送对象和接受对象的问题

生产者: image.png 统一配置返回信息

消费者: 

image.png

SpringBoot定义topic

与直连型交换机配置相同,只是再定义交换机时,定义routingKey,设置通配符

@Configuration
public class TopicRabbitConfig {
    //定义交换机名称
    private final String exchange_topic_name="topic_exchange_test";
    //定义队列名称
    private final String queue_topic_name_email = "email.topic";
    private final String queue_topic_name_qq = "qq.topic";
    @Bean
    public Queue TopicQueueEmail(){

        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue(queue_topic_name_email,true);
    }
    @Bean
    public Queue TopicQueueQq(){

        // durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
        // exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
        // autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
        //一般设置一下队列的持久化就好,其余两个就是默认false
        return new Queue(queue_topic_name_qq,true);
    }

    //声明交换机
    /**
     * CustomExchange
     * DirectExchange :直连型(routing)交换机
     * FanoutExchange :广播(订阅)交换机
     * HeadersExchange :hdeader交换机
     * TopicExchange.class :通配符交换机
     *
     * String name, 交换机名称
     * boolean durable,是否持久化
     * boolean autoDelete,是否自动删除
     * Map<String, Object> arguments 拓展参数
     */
    @Bean
    public TopicExchange getTopicExchange(){
        return new TopicExchange(exchange_topic_name,true,false,null);
    }
    @Bean
    //将队列绑定至交换机
    public Binding getBindingTopic(){
        return BindingBuilder.bind(TopicQueueEmail()).to(getTopicExchange()).with("topic.email.#");
    }

    @Bean
    //将队列绑定至交换机
    public Binding getBindingTopic1(){
        return BindingBuilder.bind(TopicQueueQq()).to(getTopicExchange()).with("topic.#");
    }

发送消息:

image.png

SpringBoot定义扇形交换机

基本流程同上,但是生产者再发送消息时,要指定routingKey为null,否则发送不到交换机上

配置消息确认回调

image.png

配置文件

image.png 在配置确认回调,测试发现无法触发回调函数,那么存在原因也许是因为版本导致的配置项不起效, 可以把publisher-confirms: true 替换为 publisher-confirm-type: correlated

配置回调函数

image.png

回调函数的四种情况:

①消息推送到server,但是在server里找不到交换机:ConfirmCallback

②消息推送到server,找到交换机了,但是没找到队列:ConfirmCallback和RetrunCallback两个回调函数

③消息推送到sever,交换机和队列啥都没找到 :ConfirmCallback

④消息推送成功 :ConfirmCallback

手动回复

配置监听容器:

image.png 配置业务处理:

image.png

basic.ack用于肯定确认

basic.nack用于否定确认(注意:这是AMQP 0-9-1的RabbitMQ扩展)

basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息

channel.basicReject(deliveryTag, true);  拒绝消费当前消息,如果第二参数传入true,就是将数据重新丢回队列里,那么下次还会消费这消息。设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。

使用拒绝后重新入列这个确认模式要谨慎,因为一般都是出现异常的时候,catch异常再拒绝入列,选择是否重入列。

但是如果使用不当会导致一些每次都被你重入列的消息一直消费-入列-消费-入列这样循环,会导致消息积压。