RabbitMQ实战(二、配置使用)

一、公共类

首先创建几个公共类,它会在消费者和生产者里都使用到

  • 消息实体类,这个根据项目需求来决定字段属性
package com.sy.rabbitmq.common.config.rabbitmq;

import lombok.Data;

import java.io.Serializable;

/**
 * @author sy
 * Date: 2019/11/25 11:35
 * @Description MQ消息实体
 */
@Data
public class MQMessage implements Serializable {


    private static final long serialVersionUID = 4426149459382531256L;
    private String messageId;
    private String message;

}
  • 交换器名、消息通道名和RoutingKey定义
package com.sy.rabbitmq.common.config.rabbitmq;

/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.10.24 16:41
 * @version:
 */
public class Constants {

    /**
     * 发送中的状态
     */
    public static final String SEND_RUN="0";
    /**
     * 发送成功
     */
    private static final String SEND_SUCCESS="1";
    /**
     * 发送失败
     */
    public static final String SEND_FAIL="2";
    /**
     * 超时时间,单位 min
     */
    public static final int SEND_TIMEOUT=1;
    /**
     * 最大重试次数
     */
    public static final int MAX_RETRY=3;


    /**
     * Fanout创建交换器
     */
    public static final String SY_FANOUT="fanout1";
    /**
     * 与Fanout交换机绑定的队列
     */
    public static final String FANOUT_DEMO1_QUEUE="fanout.demo1";
    public static final String FANOUT_DEMO2_QUEUE="fanout.demo2";

    /**
     * 创建Topic交换器
     */
    public static final String SY_TOPIC="topic1";
    /**
     * 与topic交换器绑定的队列
     */
    public static final String TOPIC_DEMO1_QUEUE="topic.demo1";
    public static final String TOPIC_DEMO2_QUEUE="topic.demo2";


    /**
     * 创建Topic的几种RoutingKey
     */
    public static final String TOPIC_ALL="topic.*";
    public static final String TOPIC_DEMO1="topic.demo1";
    public static final String TOPIC_DEMO2="topic.demo2";


    /**
     * direct 交换器
     */
    public static final String SY_DIRECT="direct1";

    public static final String DIRECT_DEMO1_QUEUE="direct1.demo1";
    public static final String DIRECT_DEMO2_QUEUE="direct1.demo2";



}
  • 一个id生成工具类(雪花id生成类)
package com.sy.rabbitmq.common.config.utils;

/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.11.16 21:29
 * @version:
 */
import java.io.Serializable;

/**
 * @author sy
 * Date: 2019/12/16 14:16
 * @Description
 */
public class IdUtils implements Serializable {

    // ==============================Fields===========================================
    /** 开始时间截 (2015-01-01) */
    private final long twepoch = 1420041600000L;

    /** 机器id所占的位数 */
    private final long workerIdBits = 5L;

    /** 数据标识id所占的位数 */
    private final long datacenterIdBits = 5L;

    /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

    /** 支持的最大数据标识id,结果是31 */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    /** 序列在id中占的位数 */
    private final long sequenceBits = 12L;

    /** 机器ID向左移12位 */
    private final long workerIdShift = sequenceBits;

    /** 数据标识id向左移17位(12+5) */
    private final long datacenterIdShift = sequenceBits + workerIdBits;

    /** 时间截向左移22位(5+5+12) */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

    /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /** 工作机器ID(0~31) */
    private long workerId;

    /** 数据中心ID(0~31) */
    private long datacenterId;

    /** 毫秒内序列(0~4095) */
    private long sequence = 0L;

    /** 上次生成ID的时间截 */
    private long lastTimestamp = -1L;

    //==============================Constructors=====================================
    /**
     * 构造函数
     * @param workerId 工作ID (0~31)
     * @param datacenterId 数据中心ID (0~31)
     */
    public IdUtils(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    public IdUtils() {
        this.workerId = 3;
        this.datacenterId = 1;
    }


    // ==============================Methods==========================================
    /**
     * 获得下一个ID (该方法是线程安全的)
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();

        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        //如果是同一时间生成的,则进行毫秒内序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            //毫秒内序列溢出
            if (sequence == 0) {
                //阻塞到下一个毫秒,获得新的时间戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        //时间戳改变,毫秒内序列重置
        else {
            sequence = 0L;
        }

        //上次生成ID的时间截
        lastTimestamp = timestamp;

        //移位并通过或运算拼到一起组成64位的ID
        return ((timestamp - twepoch) << timestampLeftShift) //
                | (datacenterId << datacenterIdShift) //
                | (workerId << workerIdShift) //
                | sequence;
    }

    /**
     * 阻塞到下一个毫秒,直到获得新的时间戳
     * @param lastTimestamp 上次生成ID的时间截
     * @return 当前时间戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    /**
     * 返回以毫秒为单位的当前时间
     * @return 当前时间(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }

    //==============================Test=============================================
    /** 测试 */
    public static void main(String[] args) {
        IdUtils idWorker = new IdUtils(4,1);
        System.out.println(idWorker.nextId());
    }


}

二、配置生产者

生产者的配置配置文件

这只是其中的一部分,挑选几个用得着的配置一下就可以了

spring:
  rabbitmq:
    host: 47.97.192.128
    port: 5672
    username: shenyao
    password: 123456
    # rabbit的目录
    virtual-host: /test
    # 开启消息确认
    publisher-confirms: true
    # 开启消息发布失败后返回
    publisher-returns: true
    # 启用强制信息
    template:
      mandatory: true
      # 尝试发布消息的最大时间间隔(默认为1000毫秒)
      retry: 
        # 是否开启重试机制
        enabled: true
        max-interval: 1000
        # 失败重试最大次数(默认为3)
        max-attempts: 3
        # 第一次与第二次发布消息的时间间隔
        initial-interval: 1000 

  #当遇到同样名字的时候,是否允许覆盖注册
  main:
    allow-bean-definition-overriding: true

消息配置

package com.sy.rabbitmq.producer.config;

import com.sy.rabbitmq.producer.rabbitmq.RabbitConfirmCallBack;
import com.sy.rabbitmq.producer.rabbitmq.RabbitReturnCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.stereotype.Component;
/**
 * @author sy
 * Date: 2019/10/20 23:01
 * @Description 关于MQ的配置
 */
@Component
@Slf4j
public class RabbitMQConfig {

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }


    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        return factory;
    }



    /**
     * 定义rabbit template用于数据的接收和发送
     * 可以设置消息确认机制和回调
     * @return
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate template = new RabbitTemplate(connectionFactory);
        // template.setMessageConverter(); 可以自定义消息转换器  默认使用的JDK的,所以消息对象需要实现Serializable
        // template.setMessageConverter(new Jackson2JsonMessageConverter());
        template.setConfirmCallback(msgSendConfirmCallBack());

        /**
         * 使用return-callback时必须设置mandatory为true,或者在配置中设置mandatory-expression的值为true,
         * 可针对每次请求的消息去确定’mandatory’的boolean值,
         * 只能在提供’return -callback’时使用,与mandatory互斥
         */
        template.setReturnCallback(msgSendReturnCallback());
        template.setMandatory(true);
        return template;
    }

    /**
     * 关于 msgSendConfirmCallBack 和 msgSendReturnCallback 的回调说明:
     * 1.如果消息没有到exchange,则confirm回调,ack=false
     * 2.如果消息到达exchange,则confirm回调,ack=true
     * 3.exchange到queue成功,则不回调return
     * 4.exchange到queue失败,则回调return(需设置mandatory=true,否则不回调,消息就丢了)
     */

    /**
     * 消息确认机制
     * Confirms给客户端一种轻量级的方式,能够跟踪哪些消息被broker处理,
     * 哪些可能因为broker宕掉或者网络失败的情况而重新发布。
     * 确认并且保证消息被送达,提供了两种方式:发布确认和事务。(两者不可同时使用)
     * 在channel为事务时,不可引入确认模式;同样channel为确认模式下,不可使用事务。
     * @return
     */
    @Bean
    public RabbitConfirmCallBack msgSendConfirmCallBack(){
        return new RabbitConfirmCallBack();
    }

    @Bean
    public RabbitReturnCallback msgSendReturnCallback(){
        return new RabbitReturnCallback();
    }


    /**
     * 生产者用 可以用来转化为json
     *
     * @return
     */
    @Bean
    public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
        RabbitMessagingTemplate rabbitMessagingTemplate = new RabbitMessagingTemplate();
        rabbitMessagingTemplate.setMessageConverter(jackson2Converter());
        rabbitMessagingTemplate.setRabbitTemplate(rabbitTemplate);
        return rabbitMessagingTemplate;
    }

    @Bean
    public MappingJackson2MessageConverter jackson2Converter() {
        return new MappingJackson2MessageConverter();
    }


}

消息发送确定类

package com.sy.rabbitmq.producer.rabbitmq;


import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;


/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.10.24 19:26
 * @version:
 */
@Slf4j
@Component
public class RabbitConfirmCallBack implements RabbitTemplate.ConfirmCallback {


    @Override
    public void confirm(@Nullable CorrelationData correlationData, boolean b, @Nullable String s) {
       // System.out.println("发送的消息为ID为"+correlationData.getId());
        if(b){
            log.info("消息推送到交换器成功");
        }else{
            log.info("消息推送到交换器失败");
            // 失败原因
            System.out.println("失败的原因:" + s);
        }
    }
}

消息推送确定类

package com.sy.rabbitmq.producer.rabbitmq;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.10.24 19:49
 * @version:
 */
@Slf4j
@Component
public class RabbitReturnCallback implements RabbitTemplate.ReturnCallback  {

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.info("----------消息从交换器推送到列队失败--------");
        log.info("消息主体: {}", message);
        log.info("回复编码: {}", replyCode);
        log.info("回复内容: {}", replyText);
        log.info("交换器: {}", exchange);
        log.info("路由键: {}", routingKey);
        log.info("----------end--------");
    }
}

配置生产者的交换器和消息通道的初始化

  • direct类型的交换器
package com.sy.rabbitmq.producer.config;

import com.sy.rabbitmq.common.config.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @author sy
 * Date: 2019/10/25 9:30
 * @Description direct交换器配置
 */
@Slf4j
@Configuration
public class DirectExchangeConfig {


    /**
     * 声明一个direct(交换机),是Fanout形式,名为Constants.SY_DIRECT(自定义的)
     * 参数说明:
     * 1、第一个为交换器名
     * 2、是否持久化,默认true
     * 3、消费者断开时是否删除
     * 4、还可以加一个消息其他参数    实际开发需要持久化,只需要输入交换器的名称,其他用默认的
     * @return
     */
    @Bean
    DirectExchange directExchange(){
        return new DirectExchange(Constants.SY_DIRECT);
    }

    /**
     * 声明一个列队,参数一:列队名为Constants.FANOUT_DEMO1_QUEUE,参数二:是否持久化
     * @return
     */
    @Bean
    Queue queue1() {
        return new Queue(Constants.DIRECT_DEMO1_QUEUE,true);
    }

    /**
     * 声明一个列队,列队名为Constants.FANOUT_DEMO2_QUEUE
     * @return
     */
    @Bean
    Queue queue2() {
        return new Queue(Constants.DIRECT_DEMO2_QUEUE, true);
    }


    /**
     * 消息通道与交换器绑定
     * @return
     */
    @Bean
    Binding fanoutQue1(){
        return BindingBuilder.bind(queue1()).to(directExchange()).with(Constants.DIRECT_DEMO1_QUEUE);
    }

    @Bean
    Binding fanoutQue2(){
        return BindingBuilder.bind(queue2()).to(directExchange()).with(Constants.DIRECT_DEMO2_QUEUE);
    }


}

  • fanout广播模式的交换器配置
package com.sy.rabbitmq.producer.config;

import com.sy.rabbitmq.common.config.Constants;
import lombok.extern.slf4j.Slf4j;
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 sy
 * Date: 2019/10/25 10:05
 * @Description fanout广播模式的交换器配置
 */
@Configuration
@Slf4j
public class FanoutExchangeConfig {

    @Bean
    FanoutExchange fanoutExchange(){
        return new FanoutExchange(Constants.SY_FANOUT);
    }


    @Bean
    Queue queue3(){
      return   new Queue(Constants.FANOUT_DEMO1_QUEUE,true);
    }

    @Bean
    Queue queue4(){
        return new Queue(Constants.FANOUT_DEMO2_QUEUE,true);
    }

    @Bean
    Binding fanoutQueue1(){
        return  BindingBuilder.bind(queue3()).to(fanoutExchange());
    }

    @Bean
    Binding fanoutQueue2(){
        return  BindingBuilder.bind(queue4()).to(fanoutExchange());
    }

}

  • topic类型的交换器
package com.sy.rabbitmq.producer.config;

import com.sy.rabbitmq.common.config.Constants;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @author sy
 * Date: 2019/10/25 9:30
 * @Description topic交换器配置
 */
@Configuration
public class TopicExchangeConfig {


    /**
     * 声明一个exchange(交换机),是top形式,名为Constants.SY_TOPIC
     * @return
     */
    @Bean
    TopicExchange topExchange(){
        return new TopicExchange(Constants.SY_TOPIC);
    }

    /**
     * 声明一个列队,列队名为Constants.TOPIC_DEMO1_QUEUE,并且持久化
     * @return
     */
    @Bean
    Queue queue5() {
        return new Queue(Constants.TOPIC_DEMO1_QUEUE,true);
    }

    /**
     * 声明一个列队,列队名为Constants.TOPIC_DEMO2_QUEUE,并且持久化
     * @return
     */
    @Bean
    Queue queue6() {
        return new Queue(Constants.TOPIC_DEMO2_QUEUE, true);
    }



    /**
     * 交换机与列队绑定,SY_TOPIC与TOPIC_DEMO2_QUEUE绑定
     * 但是我这里没
     * @return
     */
    @Bean
    Binding bindingQue1() {
        return BindingBuilder.bind(queue5()).to(topExchange())
                .with(Constants.TOPIC_DEMO1);
    }



    /**
     * topic与direct最大的区别是topic能够用符号进行匹配,
     * 我将TOPIC_DEMO2_QUEUE的列队使用Binding:TOPIC_ALL(topic.*)进行绑定。
     * @return
     */
    @Bean
    Binding bindingQue3() {
        return BindingBuilder.bind(queue6()).to(topExchange())
                .with(Constants.TOPIC_ALL);
    }
    
}

消息发送类

package com.sy.rabbitmq.producer.service.impl;

import com.sy.rabbitmq.common.config.rabbitmq.Constants;
import com.sy.rabbitmq.common.config.rabbitmq.MQMessage;
import com.sy.rabbitmq.common.config.utils.IdUtils;
import com.sy.rabbitmq.producer.service.RabbitSendService;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;


/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.11.24 17:41
 * @version:
 */
@Service
public class RabbitSendServiceImpl implements RabbitSendService {

    @Resource
    private RabbitTemplate rabbitTemplate;


    @Override
    public void sendDemo1Message(String message) {
        MQMessage mqMessage = new MQMessage();
        mqMessage.setMessage(message);
        send(Constants.SY_TOPIC,Constants.TOPIC_DEMO1_QUEUE,mqMessage);
    }

    @Override
    public void sendDemo2Message(MQMessage message) {
        send(Constants.SY_TOPIC,Constants.TOPIC_DEMO2_QUEUE,message);
    }


    @Override
    public void sendFanoutMessage(String message) {
        MQMessage mqMessage = new MQMessage();
        mqMessage.setMessage(message);
        send(Constants.SY_FANOUT,"",mqMessage);
    }


    public void send(String exchange,String routingKey,MQMessage message){
        //设置消息id,也可以用rabbit自带的,但这里我使用自己定义的消息id
        long id= new IdUtils().nextId();
        message.setMessageId(id);
        CorrelationData correlationData = new CorrelationData(id+"");
        rabbitTemplate.convertAndSend(exchange,routingKey,message,correlationData);
    }

}

消费者配置

配置文件,大概和生产者的差不多

server:
  port: 8889

spring:
  rabbitmq:
    host: 47.97.192.128
    port: 5672
    username: shenyao
    password: 123456
    virtual-host: /test
    publisher-confirms: true
    publisher-returns: true
    listener:
      direct:
        acknowledge-mode: MANUAL
      simple:
        prefetch: 1
        acknowledge-mode: manual
        retry:
          enabled: true

配置类

package com.sy.tabbitmq.consumer.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;

@Configuration
@Slf4j
public class ConsumerConfig implements RabbitListenerConfigurer {

	@Bean
	public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
		DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
		factory.setMessageConverter(new MappingJackson2MessageConverter());
		return factory;
	}

	@Bean
	public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);

		return factory;
	}

	@Override
	public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
		registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory());
	}
	
}

消息消费类

  • fanout交换器的消费类,在这里我就直接配置两个
package com.sy.tabbitmq.consumer.rabbitmq;

import com.rabbitmq.client.Channel;
import com.sy.rabbitmq.common.config.rabbitmq.Constants;
import com.sy.rabbitmq.common.config.rabbitmq.MQMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;


/**
 * @author sy
 * Date: 2019/10/25 10:25
 * @Description Fanout消息测试
 */
@Component
@Slf4j
public class FanoutMessage {

    
    @RabbitListener(queues = Constants.FANOUT_DEMO1_QUEUE)
    public void test1(@Payload MQMessage message, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        System.out.println("消息1进来");
        channel.basicAck((Long)headers.get(AmqpHeaders.DELIVERY_TAG),false);
    }


    @RabbitListener(queues = Constants.FANOUT_DEMO2_QUEUE)
    public void test2(@Payload MQMessage message, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        System.out.println(message);
        channel.basicAck((Long)headers.get(AmqpHeaders.DELIVERY_TAG),false);
    }


}

  • topic类型的消费类,测试消费重发机制
package com.sy.tabbitmq.consumer.rabbitmq;

import com.rabbitmq.client.Channel;
import com.sy.rabbitmq.common.config.rabbitmq.Constants;
import com.sy.rabbitmq.common.config.rabbitmq.MQMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * <p>
 * </p>
 *
 * @author :sy
 * @date :Created in 2019.11.24 20:33
 * @version:
 */

@Slf4j
@Component
public class Topic1Demo {

    private static int i= 0;

    @RabbitListener(queues = Constants.TOPIC_DEMO1_QUEUE)
    public void test1(@Payload MQMessage message, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        System.out.println("开始消费topic.demo1的消息:" + message.getMessage());
        if (i<5){
            i++;
            log.info("消息进入重发机制,i:"+i);
            //参数二:是否保存消息,是否重试?
            channel.basicNack((Long)headers.get(AmqpHeaders.DELIVERY_TAG),false,true);
        }else {
            log.info("消息进入正常消息,I"+i);
            channel.basicAck((Long)headers.get(AmqpHeaders.DELIVERY_TAG),false);
        }
    }

}

  • 配置普通的topic消费类
package com.sy.tabbitmq.consumer.rabbitmq;

import com.rabbitmq.client.Channel;
import com.sy.rabbitmq.common.config.rabbitmq.Constants;
import com.sy.rabbitmq.common.config.rabbitmq.MQMessage;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

/**
 * @author sy
 * Date: 2019/10/25 11:29
 * @Description
 */
@Component
public class Topic2Demo {

    @RabbitListener(queues = Constants.TOPIC_DEMO2_QUEUE)
    public void processMessage(@Payload MQMessage msg, @Headers Map<String, Object> headers, Channel channel) throws IOException {
        System.out.println("开始消费topic.demo2的消息:" + msg);
        Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        channel.basicAck(deliveryTag,false);
    }
    
}

发布了12 篇原创文章 · 获赞 20 · 访问量 3590
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览