SpringBoot整合RabbitMQ

一、pom.xml中配置

1、pom.xml中引入依赖

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

2、该依赖给容器中自动配置了

RabbitAutoConfiguration:

 rabbitMessagingTemplate:

 rabbitTemplate:

AmqpAdmin:

 

 二、配置文件中配置

前缀为 spring.rabbitmq

application.properties 中配置:
 

三、测试

1、创建Exchange、Queue、Binding

1)创建Exchange

 ​​​​​Exchange接口:从名字就可知是什么交换机(DirectExchange、FanoutExchange、CustomExchange、TopicExchange、HeadersExchange)

RabbitMQ基本使用_GoldenOakLibrarian的博客-CSDN博客关于DirectExchange、FanoutExchange、TopicExchange三种交换机的简要介绍可以转到RabbitMQ基本使用_GoldenOakLibrarian的博客-CSDN博客 

DirectExchange的全参构造器

public DirectExchange(String name, //为交换机起的名称
                        boolean durable, //是否持久化(一般填yes)
                        boolean autoDelete, //是否自动删除(一般填no)
                        Map<String, Object> arguments) //携带参数
    {
        super(name, durable, autoDelete, arguments);
    }

构造器中的参数可与下图中的各选项进行对照 ​​​​​​:

 创建交换机

@Test
public void createExchange(){
    DirectExchange directExchange = new DirectExchange("first-java-exchange",
                                                        true,false);
    amqpAdmin.declareExchange(directExchange);
}

创建成功(在 http://虚拟机地址/#/exchanges 中查看)

 2)创建Queue

Queue的全参构造器(与交换机类似)

public Queue(String name, 
            boolean durable, 
            boolean exclusive, 
            boolean autoDelete, 
            @Nullable Map<String,Object> arguments)

 创建队列

public void createQueue(){
        Queue queue = new Queue("first-java-queue",true,false,false);
        amqpAdmin.declareQueue(queue);
    }

 创建成功

 3)创建Binding

Binding 全参构造器

 public Binding(String destination, //目的地(队列或交换机名称)
                Binding.DestinationType destinationType, //目的地类型(队列或交换机)
                String exchange, //交换机
                String routingKey, //路由键
                @Nullable Map<String, Object> arguments //参数
                ) 

 创建Binding

@Test
    public void createBinding(){
        Binding binding = new Binding("first-java-queue",
                Binding.DestinationType.QUEUE,
                "first-java-exchange",
                "first.java",
                null);
        amqpAdmin.declareBinding(binding);
    }

 创建成功

 2、发送消息

1)发送字符串

@Autowired RabbitTemplate
调用rabbitTemplate.convertAndSend(name,routingKey,string)

@Test
    public void sendMessage(){
        rabbitTemplate.convertAndSend("first-java-exchange",
                                        "first.java","First Test.");
    }

 接收成功(在 http://虚拟机地址/#/queues中查看)

 2)发送对象

@ToString
@Data
public class TestEntity implements Serializable { //注意这里的序列化
    Integer id;
    String message;
    String name;
}

 调用rabbitTemplate.convertAndSend(name,routingKey,object)

    @Test
    public void sendMessage(){
        TestEntity testEntity = new TestEntity();
        testEntity.setMessage("Hello");
        testEntity.setName("June");
        testEntity.setId(1);
        rabbitTemplate.convertAndSend("first-java-exchange","first.java",testEntity);
    }

  接收成功(在 http://虚拟机地址/#/queues中查看)

接收结果 

3)MessageConverter 消息转换器

 

 Rabbit 配置消息转换器

@Configuration
public class MyRabbitConfig {
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter(); //配置消息转换器
    }
}

 接收消息(注意接收到的消息的格式)

四、接收消息

1、同一个Queue很多客户端来监听的情况 

1、只要收到消息,队列就删除消息,且只能有一个客户端收到消息。默认轮询接收消息。

2、只有一个消息完全处理完,才可以接受到下一个消息。

2、@RabbitListener(标注在类或方法上,XxxApplication上必须有 @EnableRabbit 注解)

下图为标在方法上的情况:

//Message:原生消息详细信息
//T:发送消息的类型
//queues:需要监听的所有队列
@RabbitListener(queues = {"first-java-queue"})
public void recieveMessage(Message message, TestEntity content){
    byte[] body = message.getBody();
    MessageProperties properties = message.getMessageProperties();
    System.out.println("接收到:"+message+"内容:"+content);
}
接收到:(Body:'{"id":1,"message":"Hello","name":"June"}' MessageProperties [headers=
{__TypeId__=com.atguigu.gulimall.order.entity.TestEntity}, contentType=application/json, 
contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, redelivered=false, receivedExchange=first-java-exchange, receivedRoutingKey=first.java, deliveryTag=1, consumerTag=amq.ctag-PMVlLW3jcyurz4gpZF1gWA, consumerQueue=first-java-queue])
内容:TestEntity(id=1, message=Hello, name=June)

3、@RabbitHandler(只能标注在方法上)

注意发送的路由键相同,但发送的类不同

    @Test
    public void sendMessage(){
        TestEntity testEntity = new TestEntity();
        TestEntity2 testEntity2 = new TestEntity2();
        for(int i=0;i<10;i++){
            if(i%2==0){
                testEntity.setMessage("Hello"+i);
                testEntity.setName("June");
                testEntity.setId(1);
                rabbitTemplate.convertAndSend("first-java-exchange","first.java",testEntity);
            }else{
                testEntity2.setType("num2"+i);
                testEntity2.setName("June");
                testEntity2.setId(1);
                rabbitTemplate.convertAndSend("first-java-exchange","first.java",testEntity2);
            }

        }
    }

注意接收的队列相同,但接收的类不同 (可以分别接收到对应类的消息)

@RabbitListener(queues = {"first-java-queue"})
public class recieveMessage {
    @RabbitHandler
    public void recieveMessage1(Message message, 
                                TestEntity content,
                                Channel channel){
        System.out.println("内容:"+content);
    }
    @RabbitHandler
    public void recieveMessage2(TestEntity2 content){
        System.out.println("内容:"+content);
    }
}

五、回调

1、服务收到消息就回调

在 MyRabbitConfig 中进行如下配置:
@PostConstruct (标志着会在MyRabbitConfig创建后调用)
initRabbitTemplate(){
rabbitTemplate.setConfirmCallback...}

@Configuration
public class MyRabbitConfig {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @PostConstruct //MyRabbitConfig创建完成后调用
    public void initRabbitTemplate(){
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             *
             * @param correlationData 消息唯一id
             * @param b 成功或失败:只要成功发送了消息,不管是否接受,就为true
             * @param s 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                System.out.println("correlationData:"+correlationData+" success:"+b+
                        " reason:"+s);
            }
        });
    }
}

成功接收后 打印如下结果

correlationData:null success:true reason:null

2、消息正确抵达队列才回调

在 application.properties 中进行如下配置:

# 消息抵达队列确认
spring.rabbitmq.publisher-returns=true
# 抵达队列后,异步的回调 return confirm
spring.rabbitmq.template.mandatory=true

initRabbitTemplate(){
rabbitTemplate.setReturnCallback...} 

 rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             *
             * @param message :失败的消息
             * @param i:(replyCode)回复的状态码
             * @param s:(replyText)回复的文本内容
             * @param s1:(exchange)哪个交换机
             * @param s2:(routingKey)哪个路由键
             */
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                System.out.println("message:"+message+
                                    " replyCode:"+i+
                                    " replyText:"+s+
                                    " exchange:"+s1+
                                    " routingKey:"+s2);
            }
        });

为了测试,将路由键改错,接受到下列错误消息

message:(Body:'{"id":1,"message":"Hello","name":"June"}' MessageProperties [headers={__TypeId__=com.atguigu.gulimall.order.entity.TestEntity}, contentType=application/json, contentEncoding=UTF-8, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, deliveryTag=0]) replyCode:312 replyText:NO_ROUTE exchange:first-java-exchange routingKey:first1.java

六、消费端确认机制

因为默认是自动确认,所以只要消息被消费端接收到,客户端就会自动确认,服务端就会移除这个消息。
产生问题:收到了很多消息,自动回复给服务器确认,却没有将全部消息处理成功就宕机了,此时消息丢失。 ==>解决方法:手动确认

在application.properties中进行如下配置后,只要未进行手动确认,消息就不会接收:

spring.rabbitmq.listener.simple.acknowledge-mode=manual

 签收方法

在接收方法中加入如下函数:
channel.basicAck(deliveryTag,false);业务成功的签收
channel.basicNack(deliveryTag,false,true);业务失败的拒签

    @RabbitHandler
    public void recieveMessage1(Message message, TestEntity content, Channel channel){
        System.out.println("内容:"+content);
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            channel.basicAck(deliveryTag,false); //手动签收
        }catch (Exception e){
            
        }
    }
void basicNack(long deliveryTag, 
                boolean multiple, 
                boolean requeue) //requeue=false(丢弃) =true(发回服务器重新入队) 
              throws IOException;
@RabbitHandler
    public void recieveMessage1(Message message, TestEntity content, Channel channel){
        System.out.println("内容:"+content);
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            //var3:requeue  =false(丢弃) =true(发回服务器重新入队) 
            channel.basicNack(deliveryTag,false,true);
        }catch (Exception e){

        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值