Spring Cloud 与 RabbitMQ

Posted by aclyyx on 11-08,2018

Spring Logo

统一开头:

最近的工作安排中,需要把曾经庞大的、臃肿的综合管理“大平台”拆分,引入微服务的概念;找找看看一段时间仍然不晓得微服务到底是个啥。浅薄的认为就是一个个小的、功能相对单一的服务程序。

在不明白为何物的情况下怎么快速上手?搜罗了许多文章后找到了【纯洁的微笑】的博客,里面东西不老少。其中推荐了几个开源的软件,从中找到了《Cloud-Admin》。

在《Cloud-Admin》中,分别使用到RabbitMQRedisMySQLConsul 于是开始逐个攻克。

RabbitMQ简介

看到 MQ (消息队列)就大概知道他的作用了。

RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有很多公开标准(如 COBAR的 IIOP ,或者是 SOAP 等),但是在异步消息处理中却不是这样,只有大企业有一些商业实现(如微软的 MSMQ ,IBM 的 Websphere MQ 等),因此,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等联合制定了 AMQP 的公开标准。

Docker部署RabbitMQ

为了方便开发,在 Docker 上运行 RabbitMQ 容器,通过docker search rabbitmq可以看到在镜像库中已经有了RabbitMQ镜像,在【docker doc】中也有相关的说明。

先把镜像拽下来docker pull rabbitmq,拉取最新的版本,通过下面的命令创建并运行容器。

docker run -d --hostname localhost --name springcloud-rabbitmq \
 -e RABBITMQ_DEFAULT_USER=spring -e RABBITMQ_DEFAULT_PASS=123456 \
 -p 4369:4369 -p 5672:5672 -p 25672:25672 -p 15672:15672 \
 rabbitmq
  • -d: 后台运行
  • --hostname localhost:指定hostname
  • --name springcloud-rabbitmq:指定容器的名字
  • -e RABBITMQ_DEFAULT_USER=spring:设置访问RabbitMQ的用户名
  • -e RABBITMQ_DEFAULT_PASS=123456:设置访问RabbitMQ的密码
  • -p xxxx:xxxx:绑定宿主机和容器的端口
    4369 -- erlang发现口
    5672 -- client端通信口
    15672 -- 管理界面ui端口
    25672 -- server间内部通信口

编写测试程序

测试程序参考了《Spring Boot中使用RabbitMQ》文章。

开发工具:IntelliJ IDEA 2018.2.5
Java环境:1.8.0_162
SpringBoot版本:2.1.0.RELEASE

创建项目

使用IDEA的项目创建向导。

使用Spring的项目创建向导。
Spring Initializr

Next Next 导入 RabbitMQ 的依赖 Next
选择RabbitMQ支持

创建项目后,向导已经为我们创建整个结构。
创建后的项目结构

填充代码

Maven 配置

Maven 的 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>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <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-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

Spring Boot 配置

修改配置文件 application.properties,添加如下配置

spring.application.name=rabbitmq-hello
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=spring
spring.rabbitmq.password=123456

发送者

创建消息生产者Sender。通过注入AmqpTemplate接口的实例来实现消息的发送,AmqpTemplate接口定义了一套针对AMQP协议的基础操作。在Spring Boot中会根据配置来注入其具体实现。在该生产者,我们会产生一个字符串,并发送到名为hello的队列中。

@Component
public class Sender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
        String context = "hello " + new Date();
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("hello", context);
    }
}

接收者

创建消息消费者Receiver。通过@RabbitListener注解定义该类对hello队列的监听,并用@RabbitHandler注解来指定对消息的处理方法。所以,该消费者实现了对hello队列的消费,消费操作为输出消息的字符串内容。

@Component
@RabbitListener(queues = "hello")
public class Receiver {

    @RabbitHandler
    public void process(String hello) {
        System.out.println("Receiver : " + hello);
    }
}

RabbitMQ 配置

创建RabbitMQ的配置类RabbitConfig,用来配置队列、交换器、路由等高级信息。这里我们以入门为主,先以最小化的配置来定义,以完成一个基本的生产和消费过程。

@Configuration
public class RabbitConfig {

    @Bean
    public Queue helloQueue() {
        return new Queue("hello");
    }
}

Spring Boot 主类

应用主类:

@SpringBootApplication
public class DemoApplication {

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

单元测试类

创建单元测试类,用来调用消息生产:

@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class AmqpApplicationTests {

    @Autowired
    private Sender sender;

    @Test
    public void hello() throws Exception {
        sender.send();
    }
}

运行测试

运行上面的测试用例,可以在控制台输出中看到如下信息,证明发送和接收都没有问题了。

Sender : hello Thu Nov 08 13:56:53 CST 2018
Receiver : hello Thu Nov 08 13:56:53 CST 2018

参考

《纯洁的微笑》Blog
Cloud-Admin
Spring Boot中使用RabbitMQ <--重点