RabbitMQ 12:与springboot集成+发送方确认+失败通知+手动应答

生产者:发送方确认,失败通知
消费者:手动应答

1.创建一个springboot-maven工程,pom.xml引入amqp与web

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.rabbitmq</groupId>
    <artifactId>fisher</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fisher</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
2.配置application.properties

在这里插入图片描述

spring.application.name=springboot-rabbitmq
spring.rabbitmq.host=192.168.42.111
spring.rabbitmq.port=5672
spring.rabbitmq.username=fisher
spring.rabbitmq.password=123456
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.virtual-host=fisher
3.启动类

在这里插入图片描述

package com.rabbitmq.fisher;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FisherApplication {

    public static void main(String[] args) {
        SpringApplication.run(FisherApplication.class, args);
        System.out.println("Hello World!!!");
    }
}
4.常量类Constant

在这里插入图片描述

package com.rabbitmq.fisher;

public class Constant {
    public final static String QUEUE_HELLO = "fisher.hello";
    public final static String QUEUE_USER = "fisher.user";

    public final static String TOPIC_EMAIL = "fisher.info.email";
    public final static String TOPIC_USER = "fisher.info.user";
    public final static String TOPIC_ERROR = "errorKey";

    public final static String FANOUT_A = "fisher.fanout.a";

    public final static String EXCHANGE_TOPIC = "fisher.topic.exchange";
    public final static String EXCHANGE_FANOUT = "fisher.fanout.exchange";
}
5.定义一个配置类RabbitConfig,在connectionFactory方法中设置开启发送发确认;在rabbitTemplate方法中设置失败通知,发送方确认方法,失败回调方法;在messageContainer方法中设置消费手动应答,绑定fisher.user队列,设置消费确认方法UserReceiver

在这里插入图片描述

package com.rabbitmq.fisher.config;

import com.rabbitmq.fisher.Constant;
import com.rabbitmq.fisher.hello.UserReceiver;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

    @Value("${spring.rabbitmq.host}")
    private String host;
    @Value("${spring.rabbitmq.port}")
    private String port;
    @Value("${spring.rabbitmq.username}")
    private String username;
    @Value("${spring.rabbitmq.password}")
    private String password;
    @Value("${spring.rabbitmq.virtual-host}")
    private String virtualHost;
    @Value("${spring.rabbitmq.publisher-confirms}")
    private boolean publisherConfirms;

    @Autowired
    private UserReceiver userReceiver;
    //连接工厂
    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(host + ":" + port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        //开启发送方确认
        connectionFactory.setPublisherConfirms(publisherConfirms);
        return connectionFactory;
    }

    //rabbitAdmin类封装对rabbitMq的管理操作
    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    //使用Template
    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        //失败通知
        template.setMandatory(true);
        //发送方确认
        template.setConfirmCallback(confirmCallback());
        //失败回调
        template.setReturnCallback(returnCallback());
        return template;
    }

    //使用Rabbit缺省的交换器(direct交换器)
    //申明队列
    @Bean
    public Queue helloQueue(){
        return new Queue(Constant.QUEUE_HELLO);
    }

    @Bean
    public Queue userQueue() {
        return new Queue(Constant.QUEUE_USER);
    }

    //topic exchange
    @Bean
    public Queue queueEmailMessage() {
        return new Queue(Constant.TOPIC_EMAIL);
    }

    @Bean
    public Queue queueUserMessage() {
        return new Queue(Constant.TOPIC_USER);
    }

    //申明topic交换器
    @Bean
    public TopicExchange exchange() {
        return new TopicExchange(Constant.EXCHANGE_TOPIC);
    }

    //绑定
    @Bean
    public Binding bindingEmailMessage() {
        return BindingBuilder.bind(queueEmailMessage()).to(exchange()).with("fisher.*.email");
    }
    @Bean
    public Binding bindingUserMessage() {
        return BindingBuilder.bind(queueUserMessage()).to(exchange()).with("fisher.*.user");
    }

    //fanout exchange
    //申明队列
    @Bean
    public Queue AMessage() {
        return new Queue(Constant.FANOUT_A);
    }

    //申明fanout交换器
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange(Constant.EXCHANGE_FANOUT);
    }

    //绑定
    @Bean
    public Binding bindingAMessage() {
        return BindingBuilder.bind(AMessage()).to(fanoutExchange());
    }

    //生产者发送确认
    @Bean
    public RabbitTemplate.ConfirmCallback confirmCallback(){
        return new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    System.out.println("发送者确认发送给mq成功!");
                }else {
                    System.out.println("发送者确认发送给mq失败,考虑重新发送:" + cause);
                }
            }
        };
    }
    //失败通知回调
    @Bean
    public RabbitTemplate.ReturnCallback returnCallback(){
        return new RabbitTemplate.ReturnCallback(){
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routeKey) {
                System.out.println("无法路由的消息,需要另行处理。");
                System.out.println("Return replyText:" + replyText);
                System.out.println("Return exchange:" + exchange);
                System.out.println("Return routeKey:" + routeKey);
                String msg = new String(message.getBody());
                System.out.println("Return message:" + msg);
            }
        };
    }

    //消费者确认
    @Bean
    public SimpleMessageListenerContainer messageContainer() {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
        //绑定fisher.user队列
        container.setQueues(userQueue());
        //手动提交
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        //消费确认方法,设置监听
        container.setMessageListener(userReceiver);
        return container;
    }
}
6.创建direct交换器生产者DefaultSender,分别向自动应答队列fisher.hello与手动应答队列fisher.user发送消息

在这里插入图片描述

package com.rabbitmq.fisher.hello;

import com.rabbitmq.fisher.Constant;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DefaultSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send(String msg) {
        String sendMsg = msg + "======" + System.currentTimeMillis();
        System.out.println("SendMsg:" + sendMsg);
        //普通消息处理,自动ack
        rabbitTemplate.convertAndSend(Constant.QUEUE_HELLO, sendMsg);
        //消费者处理时,有手动应答
        rabbitTemplate.convertAndSend(Constant.QUEUE_USER, sendMsg);
    }

}

7.创建自动应答消费者HelloReceiver,添加@RabbitListener(queues = “fisher.hello”)监听队列fisher.hello

在这里插入图片描述

package com.rabbitmq.fisher.hello;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fisher.hello")
public class HelloReceiver {
    @RabbitHandler
    public void process(String hello) {
        System.out.println("HelloReceiver:" + hello);
    }
}
8.创建手动应答消费者UserReceiver,实现接口ChannelAwareMessageListener,重写onMessage方法;因为在RabbitConfig中,通过container.setMessageListener(userReceiver)设置了监听,所以此处不需要加@RabbitListener(queues = “fisher.user”)

在这里插入图片描述

package com.rabbitmq.fisher.hello;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;
/**
 * 在RabbitConfig中设置了监听,所以此处不需要加@RabbitListener(queues = "fisher.user")
 **/
@Component
public class UserReceiver implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String msg = new String(message.getBody());
        System.out.println("UserReceiver>>>接收到的消息:" + msg);
        try {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            System.out.println("UserReceiver>>>消息已消费");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
            System.out.println("UserReceiver>>>消息已拒绝,要求MQ重新发送");
        }
    }
}

9.创建fanout交换器生产者FanoutSender,路由键可以不填

在这里插入图片描述

package com.rabbitmq.fisher.fanout;

import com.rabbitmq.fisher.Constant;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class FanoutSender {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send(String msg) {
        String sendMsg = msg + "==============" + System.currentTimeMillis();
        System.out.println("FanoutSender:" + sendMsg);
        rabbitTemplate.convertAndSend(Constant.EXCHANGE_FANOUT, "", sendMsg);
    }
}

10.创建fanout消费者FanoutReceiver,监听队列fisher.fanout.a

在这里插入图片描述

package com.rabbitmq.fisher.fanout;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fisher.fanout.a")
public class FanoutReceiver {
    @RabbitHandler
    public void process(String hello) {
        System.out.println("FanoutReceiver:" + hello);
    }
}

11.创建topic交换器生产者TopicSender,分别向队列fisher.info.email与队列fisher.info.user中发送消息,因为没有定义队列errorKey,所以rabbitTemplate.convertAndSend(Constant.EXCHANGE_TOPIC, Constant.TOPIC_ERROR, error)会因为无法路由,产生失败通知

在这里插入图片描述
在这里插入图片描述

package com.rabbitmq.fisher.topic;

import com.rabbitmq.fisher.Constant;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TopicSender {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void send(){
        String email = "I am email msg############";
        System.out.println("TopicSender email:" + email);
        rabbitTemplate.convertAndSend(Constant.EXCHANGE_TOPIC, Constant.TOPIC_EMAIL, email);
        String user = "I am user msg############";
        System.out.println("TopicSender user:" + user);
        rabbitTemplate.convertAndSend(Constant.EXCHANGE_TOPIC, Constant.TOPIC_USER, user);
        String error = "I am error msg############";
        System.out.println("TopicSender error:" + error);
        rabbitTemplate.convertAndSend(Constant.EXCHANGE_TOPIC, Constant.TOPIC_ERROR, error);
    }
}

12.创建topic消费者TopicEmailMessageReceiver,监听队列fisher.info.email

在这里插入图片描述

package com.rabbitmq.fisher.topic;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fisher.info.email")
public class TopicEmailMessageReceiver {
    @RabbitHandler
    public void process(String email) {
        System.out.println("TopicEmailMessageReceiver:" + email);
    }
}

13.创建topic消费者TopicUserMessageReceiver,监听队列fisher.info.user

在这里插入图片描述

package com.rabbitmq.fisher.topic;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@RabbitListener(queues = "fisher.info.user")
public class TopicUserMessageReceiver {
    @RabbitHandler
    public void process(String user) {
        System.out.println("TopicUserMessageReceiver:" + user);
    }
}

14.创建一个测试类RabbitTest

在这里插入图片描述

package com.rabbitmq.fisher.controller;

import com.rabbitmq.fisher.fanout.FanoutSender;
import com.rabbitmq.fisher.hello.DefaultSender;
import com.rabbitmq.fisher.topic.TopicSender;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/rabbit")
public class RabbitTest {
    @Autowired
    private DefaultSender defaultSender;
    @Autowired
    private FanoutSender fanoutSender;
    @Autowired
    private TopicSender topicSender;

    //普通类型测试
    @RequestMapping("/hello")
    public void hello() {
        defaultSender.send("hellomsg!");
    }

    //fanout测试
    @RequestMapping("/fanout")
    public void fanout() {
        fanoutSender.send("hellomsg!");
    }

    //topic测试
    @RequestMapping("/topic")
    public void topic() {
        topicSender.send();
    }
}
15.启动项目,请求http://localhost:8080/rabbit/hello,查看打印

在这里插入图片描述
在这里插入图片描述

SendMsg:hellomsg!======1589467774678
HelloReceiver:hellomsg!======1589467774678
UserReceiver>>>接收到的消息:hellomsg!======1589467774678
UserReceiver>>>消息已消费
发送者确认发送给mq成功!
发送者确认发送给mq成功!
16.请求http://localhost:8080/rabbit/fanout,查看打印

在这里插入图片描述

FanoutSender:hellomsg!==============1589468091019
FanoutReceiver:hellomsg!==============1589468091019
发送者确认发送给mq成功!
17.请求http://localhost:8080/rabbit/topic,查看打印

在这里插入图片描述

TopicSender email:I am email msg############
TopicSender user:I am user msg############
TopicSender error:I am error msg############
TopicEmailMessageReceiver:I am email msg############
TopicUserMessageReceiver:I am user msg############
无法路由的消息,需要另行处理。
Return replyText:NO_ROUTE
Return exchange:fisher.topic.exchange
Return routeKey:errorKey
Return message:I am error msg############
发送者确认发送给mq成功!
发送者确认发送给mq成功!
发送者确认发送给mq成功!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值