springboot整合MQ

本文介绍了如何在Spring Boot应用中集成RabbitMQ,包括配置依赖、配置文件设置、创建消息转换器,以及测试消息的发送与接收。重点讲解了消息可靠投递的实现,包括开启发送端确认、设置回调、手动确认消息以及在接收端处理消息并进行确认的过程。通过这些设置,确保消息能够准确无误地送达和处理。
摘要由CSDN通过智能技术生成

1、导入依赖

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

2、修改配置文件

spring.rabbitmq.host=192.168.3.10
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/

3、创建配置文件类

@Configuration
public class RabbitConfig {
    /**
     * 转换接收对象的数据格式,默认是java序列化的格式
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

4、测试

4.1、管理类测试

@Autowired
AmqpAdmin amqpAdmin;
/**
* 声明交换机
*/
@Test
public void createExchange() {
   DirectExchange directExchange = new DirectExchange("java.exchange",true,false);
   amqpAdmin.declareExchange(directExchange);
}

/**
* 声明队列
*/
@Test
public void createQueue() {
   Queue queue = new Queue("java.queue", true, false, false);
   amqpAdmin.declareQueue(queue);
}

4.2、消息发送与接收

消息发送:

@Autowired
RabbitTemplate rabbitTemplate;
    @Test
public void sendMessage(){
    rabbitTemplate.convertAndSend("java.exchange","","发送消息成功");
}

消息接收:

/**
 * 接收消息的方法必须在容器内
 * 第一个参数:message接收的全部内容 : 消息头+消息体
 * 第二个参数:接收的消息对象(自定义)
 * @param message
 */
@RabbitListener(queues = {"java.queue"})
public void getMessage(Message message, OrderItemEntity orderItemEntity){
    byte[] body = message.getBody();
    System.out.println("接收到消息:"+message);
}

5、拓展:消息可靠投递

5.1、修改配置文件

#开启发送端确认
spring.rabbitmq.publisher-confirms=true
#开启发送端消息抵达队列的确认
spring.rabbitmq.publisher-returns=true
#只要抵达队列,以异步发送优先回调我们这个returnConfirm
spring.rabbitmq.template.mandatory=true

#手动ack消息
spring.rabbitmq.listener.simple.acknowledge-mode=manual

5.2、修改配置类,设置发送消息的回调

设置消息抵达交换机和队列的回调:

@Configuration
public class RabbitConfig {

    @Autowired
    RabbitTemplate rabbitTemplate;
    /**
     * 转换接收对象的数据格式,默认是java序列化的格式
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    /**
     * 定制 RabbitTemplate
     * 1、服务收到消息就回调
     *      1、spring.rabbitmq.publisher-confirms=true
     *      2、设置确认回调
     * 2、消息正确抵达队列
     *      1、spring.rabbitmq.publisher-returns=true
     *         spring.rabbitmq.template.mandatory=true
     *      2、确认回调ReturnCallback
     * 3、消费端确认(保证每个消息被正确消费,此时才可以broker删除这个消息。)
     *      1、默认是自动确认的,只要消息被接受到,客户端会自动确认,服务端就会移除这个消息
     *          问题:
     *              我们收到很多消息,自动回复给服务器ack,只有一个消息处理成功,宕机了。发生消息丢失;
     *              消费者手动确认模式:只要我们没有明确告诉MQ,货物被签收;没有ack,消息就一直是unacked状态,即使consumer宕机,
     *              消息不会丢失,会重新变为Ready,下一次有新的consumer连接进来就发给他
     *       2、如何签收
     *
     */
    @PostConstruct  //相当于RabbitConfig(当前类)创建完成后执行这个方法
    public void initRabbitTemplate(){

        //设置确认回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 1、只要消息抵达broker就ack=true
             * @param correlationData 当前消息的唯一关联数据(消息的唯一ID)
             * @param ack 消息是否成功收到
             * @param cause 失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("correlationData="+correlationData+"  ack="+ack+" cause="+cause);
            }
        });
        //设置消息抵达队列的确认回调
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * 只要消息没有抵达指定的队列,就触发这个失败的回调
             * @param message 投递失败的消息详细信息
             * @param replyCode 回复的状态码
             * @param replyText 回复的文本内容
             * @param exchange 当时这个消息发给哪个交换机
             * @param routingKey 当时这个消息发给哪个路由键
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {

            }
        });
    }
}

5.3、消息接收并确认

@RabbitListener(queues = {"java.queue"})
@Service("orderItemService")
public class OrderItemServiceImpl {

    /**
     * 接收消息的方法必须在容器内 @Service @Component...
     * 第一个参数:message接收的全部内容 : 消息头+消息体
     * 第二个参数:接收的消息对象(自定义)
     * 第三个参数:当前传输数据的通道
     * @param message
     *  @RabbitListener 可以标注在 类 和 方法上
     */
    //@RabbitListener(queues = {"java.queue"})
    @RabbitHandler
    public void getMessage(Message message, OrderItemEntity orderItemEntity, Channel channel){
        byte[] body = message.getBody();
        System.out.println("接收到消息:"+message);
        //channel内按顺序递增
        long tag = message.getMessageProperties().getDeliveryTag();
        //签收货物,非批量模式
        try {
            if (tag%2 == 0) {
                //收货
                channel.basicAck(tag,false);
                System.out.println("签收了");
            } else {
                //退货 requeue=false 丢弃   requeue=true 发回服务器,重新入队
                //long deliveryTag, boolean multiple, boolean requeue
                channel.basicNack(tag,false,true);
                System.out.println("没有签收");
            }

        } catch (IOException e) {
            //网络中断
            e.printStackTrace();
        }
    }

    /**
     * @RabbitHandler 只能标注在方法上,可以接受不同的实体类,比如下方的getHandlerMessage() 和 getHandlerMessage2()
     *                可以接受同一个队列中,不同的对象类型,分类型处理
     * @param message
     * @param orderItemEntity
     * @param channel
     */
    @RabbitHandler
    public void getHandlerMessage(Message message, OrderItemEntity orderItemEntity, Channel channel){
        byte[] body = message.getBody();
        System.out.println("接收到消息:"+message);
    }

    @RabbitHandler
    public void getHandlerMessage2( OrderItemEntity orderItemEntity){
        System.out.println("接收到消息:"+orderItemEntity);
    }
}

注:@RabbitListener可以标注在类和方法上,而@RabbitHandler只能标注在方法上。两者的区别是:

  • @RabbitListener标注在方法上时可以单独使用,而@RabbitHandler需要结合@RabbitListener来一起使用(即@RabbitListener标注在类上指明监听的队列,@RabbitHandle标注在方法上,指明监听的队列的类型)
  • @RabbitListener只能处理同类型对象的队列,而@RabbitHandle可以处理不同类型对象的队列。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值