欢迎来到王晨的博客

脚踏实地,不断坚持,没有终点,永远在路上!!!
扩大
缩小

RabbitMQ消息中间件入门

第一章:RabbitMQ起步

1.1 课程导航

  • RabbitMQ简介及AMQP协议
  • RabbitMQ安装与使用
  • RabbitMQ核心概念
  • 与SpringBoot整合
  • 保障100%的消息可靠性投递方案落地实现
  • 学习源码

1.2 RabbitMQ简介

初识RabbitMQ

  • RabbitMQ是一个开源的消息代理和队列服务器
  • 用来通过普通协议在完全不同的应用之间共享数据
  • RabbitMQ是使用Erlang语言来编写的
  • 并且RabbitMQ是基于AMQP协议的

RabbitMQ简介

  • 目前很多互联网大厂都在使用RabbitMQ
  • RabbitMQ底层采用Erlang语言进行编写
  • 开源、性能优秀,稳定性保障
  • 与SpringAMQP完美的整合、API丰富
  • 集群模式丰富,表达式配置,HA模式,镜像队列模型
  • 保证数据不丢失的前提做到高可靠性、可用性
  • AMQP全称:Advanced Message Queuing Protocol
  • AMQP翻译:高级消息队列协议

AMQP协议模型

1.3 RabbitMQ安装

 

0.安装准备
官网地址:http://www.rabbitmq.com/
安装Linux必要依赖包<Linux7>
下载RabbitMQ安装包

yum install 
build-essential openssl openssl-devel unixODBC unixODBC-devel 
make gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz


1.下载:
wget www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm
wget www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm


2.相关安装配置
三个软件包的安装
修改相关配置文件
 vim /etc/hostname
 vim /etc/hosts
 (Linux防火墙)


3.修改RabbitMQ配置
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.5.7/ebin/rabbit.app
比如修改密码、配置等等;例如:loopback_users中的<<"guest">>,只保留guest
服务启动:rabbitmq-server start &
默认进程号:29123
默认端口号:5672
服务停止:rabbitmqctl app_stop


4.安装RabbitMQ web管理插件
rabbitmq-plugins enable rabbitmq_management
sudo systemctl restart rabbitmq-server
访问管控台地址:http://192.168.11.81:15672/
默认用户名密码:guest/guest

 

 

1.4 RabbitMQ概念

RabbitMQ的整体架构

RabbitMQ核心概念

  • Server:又称Broker,接受客户端的连接,实现AMQP实体服务
  • Connection:连接,应用程序与Broker的网络连接
  • Channel:网络信道

几乎所有的操作都在Channel中进行
Channel是进行消息读写的通道
客户端可建立多个Channel
每个Channel代表一个会话任务

  • Message:消息

服务器和应用程序之间传送的数据,由Properties和Body组成
Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性
Body则就是消息体内容

  • Virtual host:虚拟机

用于进行逻辑隔离,最上层的消息路由
一个Virtual host里面可以有若干个Exchange和Queue
同一个Virtual host里面不能有相同名称的Exchange或Queue

  • Exchange:交换机,接收消息,根据路由键转发消息到绑定的队列
  • Binding:Exchange和Queue之间的虚拟连接,binding中可以包含routing key
  • Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息
  • Queue:也称为Message Queue,消息队列,保存消息并将它们转发给消费者

RabbitMQ消息的流转过程

 

第二章:RabbitMQ整合SpringBoot2.x

2.1 发送消息Producer

SpringBoot与RabbitMQ集成

  • 引入相关依赖
  • 对application.properties进行配置

1、创建名为rabbitmq-producer的maven工程pom如下

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <parent>
 6         <artifactId>47-rabbitmq</artifactId>
 7         <groupId>com.myimooc</groupId>
 8         <version>1.0-SNAPSHOT</version>
 9     </parent>
10     <modelVersion>4.0.0</modelVersion>
11 
12     <artifactId>rabbitmq-producer</artifactId>
13 
14     <properties>
15         <spring.boot.version>2.0.4.RELEASE</spring.boot.version>
16     </properties>
17 
18     <dependencyManagement>
19         <dependencies>
20             <dependency>
21                 <groupId>org.springframework.boot</groupId>
22                 <artifactId>spring-boot-parent</artifactId>
23                 <version>${spring.boot.version}</version>
24                 <type>pom</type>
25                 <scope>import</scope>
26             </dependency>
27         </dependencies>
28     </dependencyManagement>
29 
30     <dependencies>
31         <dependency>
32             <groupId>org.springframework.boot</groupId>
33             <artifactId>spring-boot-starter</artifactId>
34         </dependency>
35 
36         <!--RabbitMQ依赖-->
37         <dependency>
38             <groupId>org.springframework.boot</groupId>
39             <artifactId>spring-boot-starter-amqp</artifactId>
40         </dependency>
41 
42         <!--工具类依赖-->
43         <dependency>
44             <groupId>org.apache.commons</groupId>
45             <artifactId>commons-lang3</artifactId>
46         </dependency>
47         <dependency>
48             <groupId>commons-io</groupId>
49             <artifactId>commons-io</artifactId>
50             <version>2.5</version>
51         </dependency>
52         <dependency>
53             <groupId>com.alibaba</groupId>
54             <artifactId>fastjson</artifactId>
55             <version>1.2.36</version>
56         </dependency>
57         <dependency>
58             <groupId>javax.servlet</groupId>
59             <artifactId>javax.servlet-api</artifactId>
60             <scope>provided</scope>
61         </dependency>
62         <dependency>
63             <groupId>org.slf4j</groupId>
64             <artifactId>slf4j-api</artifactId>
65         </dependency>
66         <dependency>
67             <groupId>log4j</groupId>
68             <artifactId>log4j</artifactId>
69             <version>1.2.17</version>
70         </dependency>
71 
72         <dependency>
73             <groupId>org.springframework.boot</groupId>
74             <artifactId>spring-boot-starter-test</artifactId>
75             <scope>test</scope>
76         </dependency>
77     </dependencies>
78 
79     <build>
80         <plugins>
81             <plugin>
82                 <groupId>org.springframework.boot</groupId>
83                 <artifactId>spring-boot-maven-plugin</artifactId>
84             </plugin>
85         </plugins>
86     </build>
87 
88 </project>

 

2、编写application.properties类

 1 # rabbitmq地址
 2 spring.rabbitmq.addresses=10.1.195.196:5672
 3 # rabbitmq用户名
 4 spring.rabbitmq.username=guest
 5 # rabbitmq密码
 6 spring.rabbitmq.password=guest
 7 # rabbitmq默认虚拟主机地址
 8 spring.rabbitmq.virtual-host=/
 9 # rabbitmq超时时间为15秒
10 spring.rabbitmq.connection-timeout=15000
11 
12 #字符集
13 spring.http.encoding.charset=UTF-8
14 #格式化
15 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
16 spring.jackson.time-zone=GMT+8
17 spring.jackson.default-property-inclusion=NON_NULL
18 
19 spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
20 spring.datasource.username=root
21 spring.datasource.password=
22 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
23 spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
24 
25 # 项目路径
26 server.servlet.context-path=/
27 # 服务端口号
28 server.port=8080

 

3、创建数据库

-- ----------------------------
-- Table structure for broker_message_log
-- ----------------------------
DROP TABLE IF EXISTS `broker_message_log`;
CREATE TABLE `broker_message_log` (
  `message_id` varchar(255) NOT NULL COMMENT '消息唯一ID',
  `message` varchar(4000) NOT NULL COMMENT '消息内容',
  `try_count` int(4) DEFAULT '0' COMMENT '重试次数',
  `status` varchar(10) DEFAULT '' COMMENT '消息投递状态 0投递中,1投递成功,2投递失败',
  `next_retry` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP COMMENT '下一次重试时间',
  `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  `update_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `message_id` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2018091102 DEFAULT CHARSET=utf8;

 

4、编写Order类

 1 package com.bfxy.springboot.entity;
 2 
 3 import java.io.Serializable;
 4 
 5 /**
 6  * 订单实体
 7  * @author wangc
 8  */
 9 public class Order implements Serializable {
10     private static final long serialVersionUID = -1502291609049620042L;
11     private String id;
12     private String name;
13 
14     /**
15      * 存储消息发送的唯一标识
16      */
17     private String messageId;
18 
19     public Order() {
20     }
21 
22     public Order(String id, String name, String messageId) {
23         this.id = id;
24         this.name = name;
25         this.messageId = messageId;
26     }
27 
28     public String getId() {
29         return id;
30     }
31 
32     public void setId(String id) {
33         this.id = id;
34     }
35 
36     public String getName() {
37         return name;
38     }
39 
40     public void setName(String name) {
41         this.name = name;
42     }
43 
44     public String getMessageId() {
45         return messageId;
46     }
47 
48     public void setMessageId(String messageId) {
49         this.messageId = messageId;
50     }
51 }

 

5、编写OrderSender类

 1 package com.bfxy.springboot.producer;
 2 
 3 
 4 import com.bfxy.springboot.entity.Order;
 5 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 6 import org.springframework.amqp.rabbit.support.CorrelationData;
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.stereotype.Component;
 9 
10 /**
11  * 订单消息发送者
12  *
13  * @author wangc
14  */
15 @Component
16 public class OrderSender {
17     @Autowired
18     private RabbitTemplate rabbitTemplate;
19 
20     /**
21      * 发送订单
22      *
23      * @param order 订单
24      * @throws Exception 异常
25      */
26     public void send(Order order) throws Exception {
27         CorrelationData correlationData = new CorrelationData();
28         correlationData.setId(order.getMessageId());
29         rabbitTemplate.convertAndSend("order-exchange",
30                 "order.abcd",
31                 order,
32                 correlationData);
33     }
34 }

 

6、编写OrderSenderTest类

 1 package com.bfxy.springboot;
 2 
 3 import com.bfxy.springboot.entity.Order;
 4 import com.bfxy.springboot.producer.OrderSender;
 5 import org.junit.Test;
 6 import org.junit.runner.RunWith;
 7 import org.omg.CORBA.PUBLIC_MEMBER;
 8 import org.springframework.beans.factory.annotation.Autowired;
 9 import org.springframework.boot.test.context.SpringBootTest;
10 import org.springframework.test.context.junit4.SpringRunner;
11 
12 import java.util.UUID;
13 
14 @RunWith(SpringRunner.class)
15 @SpringBootTest
16 public class SpringbootProducerApplicationTests {
17 
18     @Test
19     public void contextLoads() {
20     }
21 
22 
23     @Autowired
24     private OrderSender orderSender;
25 
26     /**
27      * 订单消息发送者测试
28      * @author wangc
29      */
30     @Test
31     public void testSend1() throws Exception {
32         Order order = new Order();
33         order.setId("201808180000000001");
34         order.setName("测试订单1");
35         order.setMessageId(System.currentTimeMillis() + "$" + UUID.randomUUID().toString());
36         orderSender.send(order);
37 
38     }
39 }

 

2.2 接收消息Cunsumer

1、编写application.properties类

 1 # SpringBoot整合rabbitMQ的基本配置:
 2 # rabbitmq地址
 3 spring.rabbitmq.addresses=10.1.195.196:5672
 4 # rabbitmq用户名
 5 spring.rabbitmq.username=guest
 6 # rabbitmq密码
 7 spring.rabbitmq.password=guest
 8 # rabbitmq默认虚拟主机地址
 9 spring.rabbitmq.virtual-host=/
10 # rabbitmq超时时间为15秒
11 spring.rabbitmq.connection-timeout=15000
12 
13 #字符集
14 #spring.http.encoding.charset=UTF-8
15 #格式化
16 #spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
17 #spring.jackson.time-zone=GMT+8
18 #spring.jackson.default-property-inclusion=NON_NULL
19 
20 spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
21 spring.datasource.username=root
22 spring.datasource.password=123456
23 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
24 spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
25 
26 # SpringBoot整合rabbitMQ 消费端配置:
27 # 基本并发:5
28 spring.rabbitmq.listener.simple.concurrency=5
29 # 签收模式:手动签收
30 spring.rabbitmq.listener.simple.acknowledge-mode=manual
31 # 最大并发:10
32 spring.rabbitmq.listener.simple.max-concurrency=10
33 # 限流策略:同一时间只有1条消息发送过来消费
34 spring.rabbitmq.listener.simple.prefetch=1
35 
36 
37 # Server配置:
38 # 项目路径
39 server.servlet.context-path=/
40 # 服务端口号
41 server.port=8082

 

2、编写OrderReceiver类

 1 package com.bfxy.springboot.consumer;
 2 
 3 import com.bfxy.springboot.entity.Order;
 4 import com.rabbitmq.client.Channel;
 5 import org.springframework.amqp.rabbit.annotation.*;
 6 import org.springframework.amqp.support.AmqpHeaders;
 7 import org.springframework.messaging.handler.annotation.Headers;
 8 import org.springframework.messaging.handler.annotation.Payload;
 9 import org.springframework.stereotype.Component;
10 
11 import java.util.Map;
12 
13 
14 /**
15  * 订单接收者
16  *
17  * @author wangc
18  */
19 @Component
20 public class OrderReceiver {
21     /**
22      * 接收消息
23      *
24      * @RabbitListener 绑定监听
25      *
26      * @param order   消息体内容
27      * @param headers 消息头内容
28      * @param channel 网络信道
29      * @throws Exception 异常
30      */
31     @RabbitListener(bindings = @QueueBinding(
32             value = @Queue(value = "order-queue", durable = "true"),
33             exchange = @Exchange(name = "order-exchange", durable = "true", type = "topic"),
34             key = "order.*"
35     )
36 
37     )
38     @RabbitHandler
39     public void onOrderMessage(@Payload Order order, @Headers Map<String, Object> headers, Channel channel) throws Exception {
40         // 消费者操作
41         System.out.println("------------收到消息,开始收费-------------------");
42         System.out.println("订单ID" + order.getId());
43         Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
44         // 手动签收消息
45 //        channel.basicAck(deliveryTag, false);
46     }
47 
48 }

 

posted on 2018-05-10 12:51  王、晨  阅读(293)  评论(0编辑  收藏  举报

导航