SpringBoot简单整合RabbitMQ

1. 引入依赖

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

2. 配置ymal

spring:
  rabbitmq:
    host: 192.168.56.10
    port: 5672
    virtual-host: /




    publisher-confirms: true  # 开启发送端确认
    publisher-returns: true # 开启发送端消息抵达队列确认
    template:
      mandatory: true  # 只要抵达队列,以异步发送优先回调我们这个returnconnfirms
    listener:
      direct:
        acknowledge-mode: manual # 手动ack消息

3.  使用java操作mq

package com.systop.gulimall.order;

import com.rabbitmq.client.ConnectionFactory;
import com.systop.common.utils.Query;
import com.systop.gulimall.order.entity.OrderEntity;
import com.systop.gulimall.order.entity.RefundInfoEntity;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
class GulimallOrderApplicationTests {

    @Autowired
    AmqpAdmin amqpAdmin;

    @Autowired
    RabbitTemplate rabbitTemplate;


    // 发布消息
    @Test
    void sendMessage(){
        String msg = "java.hello";
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setReceiverName("杜宜洲");
        orderEntity.setOrderSn("213");
        rabbitTemplate.convertAndSend("java.exchange.direct","java.hello",orderEntity);
        log.info("消息发布成功!!");

    }

    // 创建交换机
    @Test
    void createExchanges() {
        DirectExchange directExchange = new DirectExchange("java.exchange.direct", true, false);
        amqpAdmin.declareExchange(directExchange);
        log.info("交换机[{}]创建成功", "java.exchange.direct");
    }

    // 创建队列
    @Test
    void createQueue() {
        //     public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
        Queue queue = new Queue("hello-java-queue", true, false, false);
        amqpAdmin.declareQueue(queue);
        log.info("队列[{}]创建成功", "hello-java-queue");
    }

    // 交换机绑定队列
    @Test
    void binding(){
        Binding binding = new Binding("hello-java-queue", Binding.DestinationType.QUEUE, "java.exchange.direct", "java.hello", null);
        amqpAdmin.declareBinding(binding);
        log.info("交换机[{}]绑定成功", "java.exchange.direct");
    }

}

4. 使用请求发布消息

Autowired
    private RabbitTemplate rabbitTemplate;

    @ResponseBody
    @GetMapping("/send")
    public String sendMsg (){
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0){

                OrderEntity orderEntity = new OrderEntity();
                orderEntity.setReceiverName("杜宜洲"+i);
                orderEntity.setOrderSn("213"+i);
                rabbitTemplate.convertAndSend("java.exchange.direct","java.hello",orderEntity,new CorrelationData(UUID.randomUUID().toString()));
                log.info("消息发布成功!!");
            }else {
                OrderItemEntity orderItemEntity = new OrderItemEntity();
                orderItemEntity.setSkuAttrsVals("dasdf");
                orderItemEntity.setOrderId(1L);
                rabbitTemplate.convertAndSend("java.exchange.direct","java.hello22",orderItemEntity,new CorrelationData(UUID.randomUUID().toString()));

            }
        }
        return "ok";
    }

5. 接收消息

@RabbitListener(queues = {"hello-java-queue"})
@Service("orderItemService")
public class OrderItemServiceImpl extends ServiceImpl<OrderItemDao, OrderItemEntity> implements OrderItemService {




    /**
     * 参数可以写一下类型
     *  1. Message message : 原生消息详细信息. 头 + 体
     *  2. T<发送的消息的类型> : OrderReturnReasonEntity content;
     *  3. Channel channel : 当前传输数据的通道
     *
     *  Queue : 可以很多人都来监听. 只要收到消息,队列删除消息,而且只能有一个收到此消息
     *  场景:
     *   1> 订单服务启动多个; 同一个消息,之鞥你有一个客户端收到
     *   2> 只有一个消息完全处理完,方法运行结束,我们就可以接收到下一个消息
     * @param message
     * @param orderEntity
     */
    // @RabbitListener(queues = {"hello-java-queue"})
    @RabbitHandler
    public void recieveMessage(Message message, OrderEntity orderEntity, Channel channel) throws IOException {
        System.out.println("接收到消息" + orderEntity);
        byte[] body = message.getBody();

        // channel 内按顺序自增的
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        System.out.println("deliveryTag==>" + deliveryTag);
        // 手动签收,非批量模式
        try {
            if (deliveryTag % 2 == 0){
                // 收货
                channel.basicAck(deliveryTag,false);
                System.out.println("签收了货物..." + deliveryTag);
            }else {
                // 退货
                // requeue(b1) = false 丢弃  requeue=true 发回服务器,服务器重新入队
                // b: 是否批量拒收  b1: 拒收后是否重新入队
                channel.basicNack(deliveryTag,false,false);
                System.out.println("没有签收了货物");
            }
        }catch (Exception e){
            // 网络中断了
        }

    }

}

5. 因为默认的序列化机制是jdk默认的所以需要自己配置序列化,创建一个config类

package com.systop.gulimall.order.config;

import com.mysql.cj.protocol.MessageListener;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
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.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.text.SimpleDateFormat;

/**
 * @author dyz
 * @date 2022/1/11 13:40
 */
@Configuration
public class MyRabbitConfig {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }


    /**
     * 定制RabbitTemplate
     * 1. 服务收到消息就回调
     *      1. spring.rabbitmq.publisher-confirms=true
     *      2. 设置确认回调 ConfirmCallback
     * 2. 消息正确抵达队列进行回调
     *      1. spring.rabbitmq.publisher-returns=true
     *         spring.rabbitmq.template.mandatory=true
     *      2. ReturnCallback
     * 3. 消费端确认(保证每个消息被正确消费,此时才可以broker删除这个消息)
     *      1. 默认时自动确认的,只要消息接收到,客户端会自动确认,服务端就会移除这个消息.
     *          问题:
     *              我们收到很多消息,自动回复给服务器ack,只有一个消息处理成功,宕机了.发生数据丢失;
     *              手动确认模式. spring.rabbitmq.listener.direct.acknowledge-mode: manual # 手动ack消息
     *                  只要我们没有明确的告诉MQ,货物被签收.没有Ack, 消息就一直是unacked状态, 即使Consumer宕机,
     *                  消息不会丢失,会重新变为Ready,下次有新的Consumer连接进来就发给他
     */
    @PostConstruct
    public void initRabbitTemplate(){
        System.out.println(123);
        System.out.println(rabbitTemplate);
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 只要消息抵达Broker就ack(b)=true
             * @param correlationData 当前消息的唯一管来拿数据(这个是消息的唯一id)
             * @param b   消息是否成功收到
             * @param s   失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                System.out.println("confirm...correlationData["+correlationData+"] ==> ack" +"["+b+"]");
            }
        });
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * 只要消息没有投递给指定的队列,就触发这个失败的回调
             * @param message  投递失败的消息详细信息
             * @param i     回复的状态码
             * @param s     回复的文本内容
             * @param s1    当时这个消息发给那个交换机
             * @param s2    当时这个消息用的那个路由键
             */
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                System.out.println("Fail Message [" + message +"]" + "==>" + "回复的文本内容[" + s + "]");
            }
        });

    }
    
    // 这个是接收数据的时候需要配置
    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        return factory;
    }



}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值