目录
3.1 新建项目引入spring-boot-starter-amqp
3.2 添加application.properties配置
1. 消息与队列的简单介绍
消息队列(Message Queue),是分布式系统中重要的组件,可通过消息服务中间件来提升系统异步通信、扩展解耦能力。
消息服务中两个重要概念:消息代理(message broker)和目的地(destination)当消息发送者发送消息以后,将由消息代理接管,消息代理保证消息传递到指定目的地。
消息队列主要有两种形式的目的地。
- 队列(queue):点对点消息通信,发送者发送消息,消息代理收入消息,接收者从队列中获取消息,然后移出队列。
- 主题(topic):发布/订阅消息通信,发送者发送消息到主题,多个接收者监听这个主题,当消息到达时同时收到消息。
2. RabbitMQ简介和安装使用
RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。
2.1 核心概念
- Message:消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、delivery-mode(指出该消息可能需要持久性存储)等。
- Publisher:消息的生产者,也是一个向交换器发布消息的客户端应用程序。
- Exchange:交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别。
- Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
- Binding:绑定,用于消息队列和交换器之间的关联。一个绑定就是基于路由键将交换器和消息队列连接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。Exchange 和Queue的绑定可以是多对多的关系。
- Channel:信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP 命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念,以复用一条 TCP 连接。
- Consumer:消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。
- Virtual Host:虚拟主机,表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器,拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础,必须在连接时指定,RabbitMQ 默认的 vhost 是 / 。
2.2 Exchange类型
Exchange有4种类型:direct(默认),fanout, topic, 和headers,不同类型的Exchange转发消息的策略有所区别。下面具体说一下前三种的区别。
- direct:消息中的路由键(routing key)如果和 Binding 中的 binding key 一致, 交换器就将消息发到对应的队列中。路由键与队列名完全匹配。
- fanout:不处理路由键,将队列绑定与该交换器绑定的所有队列上。
- topic: 交换器通过模式匹配分配消息的路由键属性,将路由键和某个模式进行匹配,此时队列需要绑定到一个模式上。它将路由键和绑定键的字符串切分成单词,这些单词之间用点隔开。它同样也会识别两个通配符:符号“#”和符号“*”。#匹配0个或多个单词,*匹配一个单词。
2.3 RabbitMQ安装使用
RabbitMQ依然采用docker安装,比较方便快速操作,安装过程如下。
docker pull rabbitmq:3.8-management
root@ubuntu:~# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
rabbitmq 3.8-management 94fe3fd9c75f 13 hours ago 180.3 MB
rabbitmq latest f6438d62c67c 13 hours ago 150.2 MB
web latest 1807c52016d2 2 weeks ago 680.1 MB
redis latest ee077f82946a 2 weeks ago 98.22 MB
mysql latest 2ec553978d80 2 weeks ago 456.2 MB
tomcat latest 9edcbdad4d26 3 weeks ago 511.2 MB
java latest c435c0fb17b9 2 years ago 643.2 MB
docker -d -p 15672:15672 -p 5672:5672 --name myrabbitmq 94fe3fd9c75f
然后访问虚拟主机ip和端口,出现以下界面说明安装成功。
接下来先介绍一些基本操作(使用用户:guest,密码:guest进行登录):
3. SpringBoot整合使用RabbitMQ
3.1 新建项目引入spring-boot-starter-amqp
<!-- 引入的starter -->
<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>
3.2 添加application.properties配置
spring.rabbitmq.addresses=192.168.146.139
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#不写默认也是5672
spring.rabbitmq.port=5672
#不写默认是/
spring.rabbitmq.virtual-host=/
3.3 RabbitTemplate操作RabbitMQ
和JDBC,Redis相似,RabbitTemplate也可以对RabbitMQ进行操作,能够发送和接受消息。
在测试类中添加方法:
package com.chtw.rabbitmp;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBootRabbitmpApplicationTests {
@Autowired
RabbitTemplate rabbitTemplate;
//发送
@Test
public void send(){
//exchange:指定交换机,routingKey:指定路由键,object:发送数据的内容,会被jdk自动序列化
List<String> str = new ArrayList<>();
str.add("hello");
str.add("world");
str.add("哈哈哈哈");
rabbitTemplate.convertAndSend("user.direct","info",str);
}
@Test
void contextLoads() {
}
}
然后运行,登录到web管理平台去看,消息是发上去了,但是格式不是我们想要的json格式,他是被java序列化后的结果:
在RebbitTemplate中有一个MessageConverter,他默认的是SimpleMessageConverter(),就是默认使用的jdk的序列化机制。
我们添加自己的序列化器,然结果以json的数据格式保存:添加一个配置类来指定我们自己额序列化规则
package com.chtw.rabbitmp.config;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author CHTW
* @date 2019-11-07-20:50
*/
@Configuration
public class MyAMQPConfig {
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
然后在运行发送send()方法。
有发送消息,同样也有获取消息的方法:
@Test
void receive() {
Object object = rabbitTemplate.receive("info");
System.out.println(object);
}
3.4 监听消息@RabbitListener
首先我们要开启基于注解的RabbitMQ,在主类上添加一个注解来开启基于注解的RabbitMQ
为了方便测试监听功能,我们先添加一个JavaBean
package com.chtw.rabbitmp.bean;
import java.io.Serializable;
/**
* @author CHTW
* @date 2019-11-07-21:09
*/
public class User{
private int id;
private String username;
private String passwprd;
public User(){}
public User(int id,String username,String passwprd){
this.id = id;
this.username = username;
this.passwprd = passwprd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPasswprd() {
return passwprd;
}
public void setPasswprd(String passwprd) {
this.passwprd = passwprd;
}
@Override
public String toString() {
return "User:" +
"id=" + id +
", username='" + username + '\'' +
", passwprd='" + passwprd + '\'' ;
}
}
在写一个service,在service里面监听消息。
package com.chtw.rabbitmp.service;
import com.chtw.rabbitmp.bean.User;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
/**
* @author CHTW
* @date 2019-11-07-21:12
*/
@Service
public class UserService {
@RabbitListener(queues = "info")
public void RabbitListenerTest(User user){
System.out.println("用户信息:"+user);
}
}
然后再测试类里面再写一个发送用户信息的方法,
@Test
public void sendUser(){
//exchange:指定交换机,routingKey:指定路由键,object:发送数据的内容,会被jdk自动序列化
User user = new User(1,"Alice","123456789");
rabbitTemplate.convertAndSend("user.direct","info",user);
}
运行项目再运行这个发送用户的方法:
重新发送一个user对象,传一个user对象为id=1,username=Bob,password=11111;
再看控制台:
3.5 AmqpAdmin系统管理组件
AmqpAdmin提供了一些方法给我们来创建交换机、队列异界进行绑定等操作。运行以下方法,
@Test
public void amqpAdmin(){
/**
* 以declare开头的都是创建函数
* 以delete开头的都是删除函数
* removeBinding();解除绑定
*/
//创建交换机
amqpAdmin.declareExchange(new DirectExchange("user.info"));
//创建队列
amqpAdmin.declareQueue(new Queue("info.user",true));
//将队列和交换机绑定
amqpAdmin.declareBinding(new Binding("info.user", Binding.DestinationType.QUEUE,
"user.info","user.info",null));
}
本节类容到此结束
本人联系方式2329095893,欢迎各位进行学习讨论
欢迎关注熊熊出没ING公众号,不定时跟新Java、python、信息安全等相关知识哦。