RabbitMQ 学习(二)—— 在 spring 和 springboot 中使用

2 篇文章 0 订阅
1 篇文章 0 订阅


前言

记录我在 Spring 和 Springboot 中 整合使用 RabbitMQ 的项目示例。

一、Spring 整合 RabbitMQ

spring 整合 RabbitMQ 就是把创建队列、创建交换机、绑定路由 key 等等的所有公共操作都交给spring容器来进行,我们的代码只进行消息的产生发送和消费。
我们把所有的配置都放在 整合配置文件中 进行配置。没有业务代码,最后通过测试类,模拟发送消息。

1.1 生产者

1.1.1 pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-rabbitmq-producer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 引入依赖 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>

    </dependencies>

</project>

1.1.2 RabbitMQ配置信息

rabbitmq.host=192.168.191.130
rabbitmq.port=5672
rabbitmq.username=admin
rabbitmq.password=admin
rabbitmq.virtual-host=/xzk

1.1.3 整合配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/rabbit
        http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <!-- 引入 rabbitmq 的配置文件 -->
    <context:property-placeholder location="classpath:rabbitmq/rabbitmq.properties"/>

    <!-- 定义 RabbitMQ 连接工厂 -->
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>

    <!-- 定义交换机、队列 -->
    <rabbit:admin connection-factory="connectionFactory"/>

    <!-- 定义持久化队列,不存在则自动创建 -->
    <!-- 简单模式下的队列 -->
    <rabbit:queue id="spring_rabbitmq_simple_queue" name="spring_rabbitmq_simple_queue" auto-declare="true"/>

    <!-- 广播模式(发布订阅模式)-->
    <!-- 队列 -->
    <rabbit:queue id="spring_rabbitmq_fanout_queue_01" name="spring_rabbitmq_fanout_queue_01" auto-declare="true"/>
    <rabbit:queue id="spring_rabbitmq_fanout_queue_02" name="spring_rabbitmq_fanout_queue_02" auto-declare="true"/>
    <!-- 将上面的两个队列绑定到交换机上 -->
    <rabbit:fanout-exchange id="spring_rabbitmq_fanout_exchange" name="spring_rabbitmq_fanout_exchange" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding queue="spring_rabbitmq_fanout_queue_01"/>
            <rabbit:binding queue="spring_rabbitmq_fanout_queue_02"/>
        </rabbit:bindings>
    </rabbit:fanout-exchange>

    <!-- 通配符模式 -->
    <rabbit:queue id="spring_rabbitmq_topic_queue_01" name="spring_rabbitmq_topic_queue_01" auto-declare="true"/>
    <rabbit:queue id="spring_rabbitmq_topic_queue_02" name="spring_rabbitmq_topic_queue_02" auto-declare="true"/>
    <rabbit:queue id="spring_rabbitmq_topic_queue_03" name="spring_rabbitmq_topic_queue_03" auto-declare="true"/>
  	<!-- 绑定队列交换机 -->
    <rabbit:topic-exchange id="spring_rabbitmq_topic_exchange" name="spring_rabbitmq_topic_exchange" auto-declare="true">
        <rabbit:bindings>
            <rabbit:binding pattern="sjq.*" queue="spring_rabbitmq_topic_queue_01"/>
            <rabbit:binding pattern="sjq.#" queue="spring_rabbitmq_topic_queue_02"/>
            <rabbit:binding pattern="xzk.#" queue="spring_rabbitmq_topic_queue_03"/>
        </rabbit:bindings>
    </rabbit:topic-exchange>

    <!-- 定义 RabbitTemplate 对象,方便代码中操作数据 -->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>
</beans>

1.1.4 测试类

package com.kaikeba.spring.rabbitmq;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Spring 整合 RabbitMQ 测试
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/spring-rabbitmq.xml") // classpath: 与后面的路径之间不能有空格 classpath: spring/spring-rabbitmq.xml 就会报错
public class SpringRabbitTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 只发送队列消息
     * 使用默认交换机,类型为 Direct
     * 交换机名称与队列同名
     */
    @Test
    public void simpleQueueTest() {
        // 路由键与队列同名
        rabbitTemplate.convertAndSend("spring_rabbitmq_simple_queue", "直接发送到队列中的消息!!!");
    }

    /**
     * 发送广播信息
     * 交换机类型为 fanout
     * 绑定到该交换机上的所有队列都能收到消息
     */
    @Test
    public void  fanoutQueueTest() {
        rabbitTemplate.convertAndSend("spring_rabbitmq_fanout_exchange", "", "fanout 广播模式的消息,绑定到这个交换机上的队列都能收到!!");
    }


    /**
     * 通配符模式
     * 交换机类型为 Topic
     * 匹配路由键的通配符,* 只匹配一个单词, # 匹配若干个(一个或多个)
     * 绑定到该交换机的匹配队列,能够接收到对应的消息。
     */
    @Test
    public void  topicQueueTest() {
        rabbitTemplate.convertAndSend("spring_rabbitmq_topic_exchange", "sjq.first", "routing key is sjq.first  send message test");
        rabbitTemplate.convertAndSend("spring_rabbitmq_topic_exchange", "sjq.second.lll","routing key is sjq.second.lll .....");
        rabbitTemplate.convertAndSend("spring_rabbitmq_topic_exchange","xzk.cn.com","路由key是xzk.xn.com,jiandancieh");
    }

}

1.1.5 测试结果

1.1.5.1 交换机、队列

spring容器启动的时候,就会将配置好的交换机和队列都生成出来。

  • 交换机
    在这里插入图片描述
  • 队列
    在这里插入图片描述
  • 交换机队列绑定关系
    请添加图片描述
    请添加图片描述
1.1.5.2 队列中的消息
  • 队列
    请添加图片描述
  • 广播模式
    请添加图片描述
  • 通配符模式
    请添加图片描述请添加图片描述
    请添加图片描述

1.2 消费者

1.2.1 pom.xml

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-rabbitmq-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit</artifactId>
            <version>2.1.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
    </dependencies>

</project>

1.2.2 RabbitMQ 配置

rabbitmq.host=192.168.191.130
rabbitmq.port=5672
rabbitmq.username=admin
rabbitmq.password=admin
rabbitmq.virtual-host=/xzk

1.2.3 spring-rabbitmq配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rabbit="http://www.springframework.org/schema/rabbit"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/rabbit
        http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">

    <!-- 引入 rabbitmq 的配置文件 -->
    <context:property-placeholder location="classpath:rabbitmq/rabbitmq.properties"/>

    <!-- 定义 RabbitMQ 连接工厂 -->
    <rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}"
                               port="${rabbitmq.port}"
                               username="${rabbitmq.username}"
                               password="${rabbitmq.password}"
                               virtual-host="${rabbitmq.virtual-host}"/>

    <!-- 定义 RabbitTemplate 对象,方便代码中操作数据 -->
    <rabbit:template id="rabbitTemplate" connection-factory="connectionFactory"/>

    <!-- 监听器 -->
    <bean id="springRabbitSimpleQueueListener" class="com.kaikeba.spring.rabbit.listener.SpringRabbitSimpleQueueListener"/>
    <bean id="springRabbitFanoutQueue01" class="com.kaikeba.spring.rabbit.listener.SpringRabbitFanoutQueue01"/>
    <bean id="springRabbitFanoutQueue02" class="com.kaikeba.spring.rabbit.listener.SpringRabbitFanoutQueue02"/>
    <bean id="springRabbitTopicQueue01" class="com.kaikeba.spring.rabbit.listener.SpringRabbitTopicQueue01"/>
    <bean id="springRabbitTopicQueue02" class="com.kaikeba.spring.rabbit.listener.SpringRabbitTopicQueue02"/>
    <bean id="springRabbitTopicQueue03" class="com.kaikeba.spring.rabbit.listener.SpringRabbitTopicQueue03"/>
    <!-- 监听队列 -->
    <rabbit:listener-container connection-factory="connectionFactory" auto-declare="true">
        <rabbit:listener ref="springRabbitSimpleQueueListener" queue-names="spring_rabbitmq_simple_queue"/>
        <rabbit:listener ref="springRabbitFanoutQueue01" queue-names="spring_rabbitmq_fanout_queue_01"/>
        <rabbit:listener ref="springRabbitFanoutQueue02" queue-names="spring_rabbitmq_fanout_queue_02"/>
        <rabbit:listener ref="springRabbitTopicQueue01" queue-names="spring_rabbitmq_topic_queue_01"/>
        <rabbit:listener ref="springRabbitTopicQueue02" queue-names="spring_rabbitmq_topic_queue_02"/>
        <rabbit:listener ref="springRabbitTopicQueue03" queue-names="spring_rabbitmq_topic_queue_03"/>
    </rabbit:listener-container>
</beans>

1.2.4 测试类

消费者的测试类,目的只是启动 spring 容器。让对应队列的监听器开始工作,所以我们写个死循环。

package com.kaikeba.spring.rabbit.listener;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring/spring-rabbitmq.xml")
public class AllTest {

    /**
     * 没有代码,仅仅是为了启动容器
     */
    @Test
    public void test() {
        while (true) {

        }
    }
}

1.2.5 监听类

我们每个监听类除了类名之外,完全相同,所以我们只放一个监听类的代码:

package com.kaikeba.spring.rabbit.listener;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;

import java.io.UnsupportedEncodingException;

/**
 * 接收消息:队列监听器
 */
public class SpringRabbitSimpleQueueListener implements MessageListener {
    public void onMessage(Message message) {
        try {
            String msg = new String(message.getBody(), "UTF-8");
            System.out.println("接收路由名为:" + message.getMessageProperties().getReceivedExchange());
            System.out.println("路由 key 为:" + message.getMessageProperties().getReceivedRoutingKey());
            System.out.println("队列名为:" + message.getMessageProperties().getConsumerQueue());
            System.out.println("接收的消息为:" + msg);
            System.out.println("==================================================================================");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

1.2.6 测试结果

控制台查看监听器的输出:
请添加图片描述

二、springboot 整合 RabbitMQ

2.1 介绍

在 Spring 项目中,可以使用 Spring-Rabbit 去操作 RabbitMQ
尤其是在 Springboot 项目中只需要引入对应的 amqp 启动依赖就可以使用, 方便的使用RabbitTemplate发 送消息,使用注解接收消息。

  • 生产者工程:
  1. 在 yml 或 properties 配置文件配置 RabbitMQ 的相关信息;
  2. 在生产只工程中编写配置类,创建交换机、队列 并 进行绑定;
  3. 注入 RabbitTemplate 对象, 通过RabbitTemplate对象发送消息到交换机 。

消费者工程:

  1. 在 yml 或 properties 配置文件配置 RabbitMQ 的相关信息;
  2. 创建消息处理类,用于接收队列中的消息并进行处理 。

2.2 生产者工程

2.2.1 pom.xml

<?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 http://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.1.4.RELEASE</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>springboot-rabbitmq-producer</artifactId>
    <version>1.0-SNAPSHOT</version>

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

2.2.2 RabbitMQ配置

spring.rabbitmq.host=192.168.191.130
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/xzk

2.2.3 配置类

package com.kaikeba.springboot.rabbitmq.configuration;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ 配置文件
 */
@Configuration
public class RabbitMQConfiguration {
    //交换机名称
    public static final String ITEM_TOPIC_EXCHANGE = "springboot_item_topic_exchange";
    //队列名称
    public static final String ITEM_QUEUE = "springboot_item_queue";

    /**
     * 声明交换机
     */
    @Bean("itemTopicExchange")
    public Exchange topicExchange() {
        return ExchangeBuilder.topicExchange(ITEM_TOPIC_EXCHANGE).durable(true).build();
    }

    /**
     * 声明队列
     */
    @Bean("itemQueue")
    public Queue itemQueue() {
        return QueueBuilder.durable(ITEM_QUEUE).build();
    }

    /**
     * 绑定交换机和队列
     */
    @Bean
    public Binding itemQueueExchange(@Qualifier("itemQueue") Queue queue, @Qualifier("itemTopicExchange") Exchange itemTopicExchange) {
        return BindingBuilder.bind(queue).to(itemTopicExchange).with("item.#").noargs();
    }
}

2.2.4 启动类

package com.kaikeba.springboot.rabbitmq;

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

@SpringBootApplication
public class SpringBootRabbitMQProducerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRabbitMQProducerApplication.class, args);
    }
}

2.2.5 测试类

package com.kaikeba.springboot.rabbitmq;

import com.kaikeba.springboot.rabbitmq.configuration.RabbitMQConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMQProducerTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void test() {
        rabbitTemplate.convertAndSend(RabbitMQConfiguration.ITEM_TOPIC_EXCHANGE, "item.insert", "商品新增,routing key 为item.insert");
        rabbitTemplate.convertAndSend(RabbitMQConfiguration.ITEM_TOPIC_EXCHANGE, "item.update", "商品修改,routing key 为item.update");
        rabbitTemplate.convertAndSend(RabbitMQConfiguration.ITEM_TOPIC_EXCHANGE, "item.delete", "商品删除,routing key 为item.delete");
    }
}

2.2.6 测试结果

  • 交换机
    在这里插入图片描述

  • 绑定关系
    在这里插入图片描述

  • 队列
    在这里插入图片描述

  • 消息
    在这里插入图片描述

2.3 消费者工程

2.3.1 pom.xml

<?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 http://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.1.4.RELEASE</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>springboot-rabbitmq-consumer</artifactId>
    <version>1.0-SNAPSHOT</version>

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

2.3.2 RabbitMQ 配置

spring.rabbitmq.host=192.168.191.130
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.virtual-host=/xzk

2.3.3 监听类

package com.kaikeba.springboot.rabbitmq.listener;

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

@Component
public class QueueListener  {

    @RabbitListener(queues = "springboot_item_queue")
    public void  listenQueue(String message) {
        System.out.println("消费者接收到的消息为:" + message);
    }
}

2.3.4 启动类

package com.kaikeba.springboot.rabbitmq;

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

@SpringBootApplication
public class SpringBootRabbitMQConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootRabbitMQConsumerApplication.class, args);
    }
}

2.3.5 测试类

测试类的目的是启动项目,使得监听类正常工作,所以没有逻辑代码:

package com.kaikeba.springboot.rabbitmq;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRabbitMQConsumerTest {

    @Test
    public void test() {
        while (true) {

        }
    }
}

2.3.6 测试结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值