RabbitMQ从入门到精通(三)rabbitMQ整和springboot

因项目紧急所以停更了一段时间,废话不多说,直接开始干货。
因为这几种模式在我的前面几篇博客中已经详细介绍了,不清楚的可以回顾我的上一篇博客进行系统的学习。现在直接开始整和代码,其实和java连接区别不大。

首先新建一个maven项目

生产者的maven的依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-launcher</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

生产者的项目结构为:
在这里插入图片描述
生产者的application.yml配置文件中的配置为:

server:
  port: 8080

spring:
  application:
    name: producer
  rabbitmq:
    host: localhost
    port: 5672
    username: test
    password: 123456
    virtual-host: v-test
    #消息到达交换机进行通知,默认是不做通知
    publisher-confirm-type: correlated    #开启消息到达交换机的确认机制
    publisher-returns: true    #消息由交换机到达队列时失败出发

使用的rabbitmq的账号和之前文章中用的的账号一样,大家可以在rabbitmq客户端操作界面上自行操作创建自己的账号。

另创建一个maven项目作为消费者

maven依赖和生产者的maven依赖一样
消费者的项目结构为:
在这里插入图片描述
消费者的application.yml配置为:

server:
  port: 8081

spring:
  application:
    name: producer
  rabbitmq:
    host: localhost
    port: 5672
    username: test
    password: 123456
    virtual-host: v-test

注意,生产者和消费者的端口号不能重复,否则不能启动项目。

开始RabbitMQ五种模式的测试

1.简单模式
包含一个生产者、一个消费者和一个队列,生产者向队列发送消息,消费者从队列中获取并消费消息。
在这里插入图片描述

P为生产者,C为消费者,中间为消息队列,下面我们简单的用代码实现。
生产者新建SendRabbitMQConfig设置类

@Configuration
public class SendRabbitMQConfig {

    /**
     * 创建一个队列
     * @return
     */
    @Bean
    public Queue hello(){
        return new Queue("hello");
    }
}

生产者新建一个测试类并且注入rabbitTemplate,并且测试是否成功注入。

@SpringBootTest
class SpringbootRabbitmqApplicationTests {


    @Autowired
    private RabbitTemplate rabbitTemplate;
    }
    
    @Test
    void contextLoads() {
        System.out.println(rabbitTemplate);
    }

生产者添加直连模式的发送代码

    /**
     * 直连模型的消息发送
     */
    @Test
    void sendHello() {
        rabbitTemplate.convertAndSend("hello", "hello world");
        System.out.println("消息发送成功");
    }

消费者接收代码

/**
 * @author: BigGreysheep
 *
 * 消费者(直连模式)
 */
@Component
@RabbitListener(queuesToDeclare = {@Queue("hello")})
public class Coustmer {

    @RabbitHandler
    public void receiveMessage(String body){
        System.out.println("消费者收到消息,内容为:"+body);

    }
}

先启动消费者再启动生产者结果为:
在这里插入图片描述
消费者接收的结果:
在这里插入图片描述
2.工作模式(workPattern)
工作模式是指多个相互竞争的消费者发送消息的模式,它包含一个生产者、两个消费者和一个队列。两个消费者同时绑定到一个队列上去,当消费者获取消息处理耗时任务时,空闲的消费者从队列中获取b并消费队列。
在这里插入图片描述

生产者的Config代码

@Configuration
public class WorkConfig {

    /**
     * 创建一个队列
     * @return
     */
    @Bean
    public Queue work(){
        Queue work = new Queue("work");
        return work;
    }
}

在发送测试类中添加第二种方法的发送代码:

  /**
     * 第二种模型的消息发送
     */
    @Test
    void sendWork() {
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work", "hello world-----" + i);
        }
        System.out.println("消息发送完成");
    }

消费者的消费代码

@Component
public class WorkCoustmer {

    @RabbitListener(queuesToDeclare = {@Queue("work")})
    public void receiveMessage1(String body) {
        System.out.println("消费者[1]收到消息,内容为:" + body);
    }


    @RabbitListener(queuesToDeclare = {@Queue("work")})
    public void receiveMessage2(String body) {
        System.out.println("消费者[2]收到消息,内容为:" + body);
    }

}

运行的结果为:
在这里插入图片描述
在这里插入图片描述
3.发布/订阅模式(fanout)
指同时向多个消费者发送消息的模式(类似广播),它包括一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上,两个队列绑定到交换机上去,生产者通过发送消息到交换机,所有消费者接收并消费消息。
在这里插入图片描述
生产者的Config


public class FanoutConfig {
    /**
     * 声明交换机
     */
    @Bean
    public FanoutExchange fanoutExange() {
        FanoutExchange fanoutExchange = new FanoutExchange("logs");
        return fanoutExchange;
    }

    /**
     * 声明队列1
     */
    @Bean
    public Queue fanoutQueue1() {
        Queue queue = new Queue("fanout_queue1");
        return queue;
    }

    /**
     * 声明队列2
     */
    @Bean
    public Queue fanoutQueue2() {
        Queue queue = new Queue("fanout_queue2");
        return queue;
    }

    /**
     * 队列1绑定交换机
     */
    @Bean
    public Binding binding1(){
        Binding binding= BindingBuilder.bind(fanoutQueue1()).to(fanoutExange());
        return binding;
    }


    /**
     * 队列2绑定交换机
     */
    @Bean
    public Binding binding2(){
        Binding binding= BindingBuilder.bind(fanoutQueue2()).to(fanoutExange());
        return binding;
    }
}

在发送测试类中添加第三种方法的发送代码:

 /**
     * 第三种模型的消息发送(fanout)
     */
    @Test
    void sendFanout() {
        rabbitTemplate.convertAndSend("logs", "", "这是一个fanout的日志消息");
        System.out.println("消息发送完成");
    }

消费者的接收代码:

@Component
public class FanoutCoustmer {

    /**
     * 接收第一个队列里的信息
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(   //把队列和交换机进行绑定
            value=@Queue("fanout_queue1"),  //绑定队列
            exchange = @Exchange(name = "logs",type= ExchangeTypes.FANOUT)   //绑定交换机

    ))
    public void receive1(String message){
        System.out.println("消费者【1】接收到消息"+message);
    }

    /**
     * 接收第二个队列里的信息
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(
            value=@Queue("fanout_queue2"),
            exchange = @Exchange(name = "logs",type= ExchangeTypes.FANOUT)

    ))
    public void receive2(String message){
        System.out.println("消费者【2】接收到消息"+message);
    }
    }

生产者的运行结果
在这里插入图片描述
消费者运行结果
在这里插入图片描述
4.路由模式
路由模式是可以根据路由键选择性给多个消费者发送消息的模式,它包括一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的不同的队列上去,两个队列通过路由键绑定到交换机上,生产者发送消息到交换机,交换机通过路由键转发到不同队列,队列绑定的消费者接受消息。
在这里插入图片描述
生产者的Config

@Configuration
public class RoutingDirectConfig {
    /**
     * 声明交换机
     */
    @Bean
    public DirectExchange directExange() {
        DirectExchange directExchange = new DirectExchange("directs");
        return directExchange;
    }
}

在发送测试类中添加第四种发送代码:

  /**
     * 第四种模型的消息发送(RoutingDirect)
     */
    @Test
    void sendRoutingDirect() {
        rabbitTemplate.convertAndSend("directs", "info", "info的日志信息");
        rabbitTemplate.convertAndSend("directs", "warm", "warm的日志信息");
        rabbitTemplate.convertAndSend("directs", "debug", "debug的日志信息");
        rabbitTemplate.convertAndSend("directs", "error", "error的日志信息");
        System.out.println("消息发送成功");
    }

运行结果:
在这里插入图片描述
在这里插入图片描述
因没有创建消费者四所以没有接收到warm消息,此知识点后面会说。
5.通配符模式
通配符模式是可以根据路由键匹配规则选择性给多个消费者发送消息的模式,它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列通过路由键匹配规则绑定到交换机上去,生产者发送消息到交换机,交换机通过路由键匹配规则转发到不同队列,队列绑定的消费者接收并消费消息。
在这里插入图片描述
生产者的Config

@Configuration
public class RoutingTopicConfig {
    /**
     * 声明交换机
     */
    @Bean
    public TopicExchange topicExchange() {
        TopicExchange topicExchange = new TopicExchange("topic");
        return topicExchange;
    }
    /**
     * 声明队列1
     */
    @Bean
    public Queue fanoutQueue1() {
        Queue queue = new Queue("topic_queue1");
        return queue;
    }

    /**
     * 声明队列2
     */
    @Bean
    public Queue fanoutQueue2() {
        Queue queue = new Queue("topic_queue2");
        return queue;
    }

    /**
     * 队列1绑定交换机
     */
    @Bean
    public Binding binding1(){
        Binding binding= BindingBuilder.bind(fanoutQueue1()).to(topicExchange()).with("user.*");
        return binding;
    }


    /**
     * 队列2绑定交换机
     */
    @Bean
    public Binding binding2(){
        Binding binding= BindingBuilder.bind(fanoutQueue2()).to(topicExchange()).with("user.#");
        return binding;
    }
}

生产者发送消息的测试代码

    /**
     * 第五种模型的消息发送(RoutingTopic)
     */
    @Test
    void sendRoutingTopic() {
        rabbitTemplate.convertAndSend("topic", "user.save", "用户的保存操作");
        rabbitTemplate.convertAndSend("topic", "user.update", "用户的更新操作");
        rabbitTemplate.convertAndSend("topic", "user", "用户的操作");
    }

消费者的消费端代码

@Component
public class RoutingTopicCoustmer {
    /**
     * 接收第一个队列里的信息
     * *匹配路由键的一个词
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(   //把队列和交换机进行绑定
            value=@Queue(value = "topic_queue1", durable = "true", autoDelete = "false"),     //绑定队列
            key = {"user.*"},
            exchange = @Exchange(name = "topic",type= ExchangeTypes.TOPIC)   //绑定交换机
    ))
    public void receive1(String message){
        System.out.println("消费者【1】接收到消息"+message);
    }


    /**
     * 接收第二个队列里的信息
     * #号匹配路由键的一个或多个词
     * @param message
     */
    @RabbitListener(bindings = @QueueBinding(   //把队列和交换机进行绑定
            value=@Queue(value = "topic_queue2", durable = "true", autoDelete = "false"),     //绑定队列
            key = {"user.#"},
            exchange = @Exchange(name = "topic",type= ExchangeTypes.TOPIC)   //绑定交换机
    ))
    public void receive2(String message){
        System.out.println("消费者【2】接收到消息"+message);
    }
}

运行结果:
在这里插入图片描述
在这里插入图片描述

消息监听类

生产者的消息监听类

@Component
public class WatchMessageImpl implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void initRabbitTemplate(){
        rabbitTemplate.setReturnsCallback(this);
        rabbitTemplate.setConfirmCallback(this);
    }


    /**
     * 当消息到达交换机之后触发(到达交换机之后,该方法会被回调)
     *
     * @param correlationData 相关数据
     * @param ack             交换机接收消息是否成功
     * @param cause           如果没有成功,返回原因
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if (ack) {
            System.out.println("交换机接收消息成功");
        } else {
            System.out.println("交换机接收消息失败,失败原因是:" + cause);
        }
    }


    /**
     * 消息如果未正常到达队列里面 会回调
     *
     * @param returnedMessage 消息内容  回调相应码  响应文本  交换机  路由key
     */
    @Override
    public void returnedMessage(ReturnedMessage returnedMessage) {
        System.out.println("队列未接收到消息");
        System.out.println("ReplyText:" + returnedMessage.getReplyText());
        System.out.println("RoutingKey:" + returnedMessage.getRoutingKey());
        System.out.println("ReplyCode:" + returnedMessage.getReplyCode());
        System.out.println("Message:" + returnedMessage.getMessage());

    }
}

手动签收:

 @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "mac_id", durable = "true", autoDelete = "false"),
            exchange = @Exchange(value = "data", type = ExchangeTypes.DIRECT), key = "MAC"))
    @RabbitHandler
    public void receivedHomeMac(Message message, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag, Channel channel)
            throws IOException {

        boolean result = true;
        try {
            log.info("数据接收成功", message);
        } catch (Exception e) {
            log.error("数据同步异常,", e);
            result = false;
        }
        if (result) {
            // RabbitMQ的ack机制中,第二个参数返回true,表示需要将这条消息投递给其他的消费者重新消费(不用改)
            channel.basicAck(deliveryTag, false);
        } else {
            /**
             * 参数说明:
             *
             * 参数一:要签收的投递ID是多少
             * 参数二:是否批量签收
             * 参数三:true;拒绝签收并将消息重新放回消息队列里面    false;拒绝签收,消息不放回消息队列里面
             */
            channel.basicNack(deliveryTag, false, true);
        }
    }
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值