springboot整合RabbitMQ,实现消息生产消费例子

一、导入maven包

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

二、属性配置

在application.properties下写入:

####rabitmq配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username={}
spring.rabbitmq.password={}

三、新增配置类

在这里,定义了几个exchange、queue以及路由绑定:

  • 将队列A绑定到交换机A,路由是ROUTINGKEY_A
  • 将队列B绑定到交换机A,路由是ROUTINGKEY_B
@Configuration
public class RabbitMQConfig {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${spring.rabbitmq.host}")
    private String host;

    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    // Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
    public static final String EXCHANGE_A = "lin-mq-exchange_A";
    public static final String EXCHANGE_B = "lin-mq-exchange_B";
    public static final String EXCHANGE_C = "lin-mq-exchange_C";

    // Queue:消息的载体,每个消息都会被投到一个或多个队列。
    public static final String QUEUE_A = "LIN_QUEUE_A";
    public static final String QUEUE_B = "LIN_QUEUE_B";
    public static final String QUEUE_C = "LIN_QUEUE_C";

    // Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
    public static final String ROUTINGKEY_A = "lin_spring-boot-routingKey_A";
    public static final String ROUTINGKEY_B = "lin_spring-boot-routingKey_B";
    public static final String ROUTINGKEY_C = "lin_spring-boot-routingKey_C";

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost("/");
        connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.SIMPLE);
        return connectionFactory;
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    //必须是prototype类型
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        return template;
    }

    @Bean
    public DirectExchange defaultExchange() {
        return new DirectExchange(EXCHANGE_A);
    }
    @Bean
    public Queue queueA() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-queue-type", "classic");
        return new Queue(QUEUE_A, true, false, false, args); //队列持久
    }
    @Bean
    public Queue queueB() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-queue-type", "classic");
        return new Queue(QUEUE_B, true, false, false, args); //队列持久
    }

    /**
     * @Author: ljq
     * @description:将队列A绑定到交换机A
     * @Param: []
     * @Return: org.springframework.amqp.core.Binding
     */
    @Bean
    public Binding binding() {
        return BindingBuilder.bind(queueA()).to(defaultExchange()).with(RabbitMQConfig.ROUTINGKEY_A);
    }

    /**
     * @Author: ljq
     * @description:一个交换机可以绑定多个消息队列,将队列B绑定到交换机A
     * @Param: []
     * @Return: org.springframework.amqp.core.Binding
     */
    @Bean
    public Binding bindingB(){
        return BindingBuilder.bind(queueB()).to(defaultExchange()).with(RabbitMQConfig.ROUTINGKEY_B);
    }

}

四、生产者

@Component
public class MsgProducer implements RabbitTemplate.ConfirmCallback{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private RabbitTemplate rabbitTemplate;

    /**
     * 由于config配置类中rabbitTemplate的scope属性设置为ConfigurableBeanFactory.SCOPE_PROTOTYPE,所以不能自动注入
     * 这里用构造方法注入rabbitTemplate
     */
    @Autowired
    public MsgProducer(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setConfirmCallback(this); //rabbitTemplate如果为单例的话,那回调就是最后设置的内容
    }

    /**
     * @Author: ljq
     * @description: 发送消息
     * @Param: [content]
     * @Return: void
     */
    public void sendMsg(String exchange, String routingKey, String content) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        //把消息放入ROUTINGKEY_A对应的队列当中去,对应的是队
        rabbitTemplate.convertAndSend(exchange, routingKey, content, correlationData);
    }

    /**
     * @Author: ljq
     * @description:回调函数
     * @Param: [correlationData, b, s]
     * @Return: void
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
        logger.info(" 回调id:" + correlationData);
        if (b) {
            logger.info("消息成功发送");
        } else {
            logger.info("消息发送失败:" + s);
        }

    }
}

五、消费者

@Component
@RabbitListener(queues = RabbitMQConfig.QUEUE_A)
public class MsgReceiver {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @RabbitHandler
    public void process(String content) {
        String str = "我已接收到队列A的消息,消息内容为:" + content;
        logger.info(str);
    }
}

六、测试

这里测试的是路由A

@RestController
@RequestMapping("/v0.1/mq")
public class SendMsgController {

    @Autowired
    private MsgProducer producer;

    @PostMapping("")
    public void sendMsg() {
        String content = "test";
        for (int i = 0; i < 10; i++) {
            producer.sendMsg(RabbitMQConfig.EXCHANGE_A, RabbitMQConfig.ROUTINGKEY_A, content + i);
        }
    }
}

七、另一种消息消费者的写法

在配置类中增加对队列B的监听:

/**
     * @Author: ljq
     * @description: 消息消费者,对队列B进行监听
     * @Param: []
     * @Return: org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer() {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
        container.setQueues(queueB());
        container.setExposeListenerChannel(true);
        container.setMaxConcurrentConsumers(1);
        container.setConcurrentConsumers(1);
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL); //设置确认模式手工确认
        container.setMessageListener(new ChannelAwareMessageListener() {

            @Override
            public void onMessage(Message message, Channel channel) throws Exception {
                byte[] body = message.getBody();
                System.out.println("队列B接受消息 " + new String(body));
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); //确认消息成功消费
            }
        });
        return container;
    }

Controller中路由改为:
producer.sendMsg(RabbitMQConfig.EXCHANGE_A, RabbitMQConfig.ROUTINGKEY_B, content + i);

@RestController
@RequestMapping("/v0.1/mq")
public class SendMsgController {

    @Autowired
    private MsgProducer producer;

    @PostMapping("")
    public void sendMsg() {
        String content = "test";
        for (int i = 0; i < 10; i++) {
            producer.sendMsg(RabbitMQConfig.EXCHANGE_A, RabbitMQConfig.ROUTINGKEY_B, content + i);
        }
    }
}

推荐阅读更多精彩内容