RabbitMQ总结
一、MQ的基本概念
- MQ概述
- MQ,消息队列,存储消息的中间件。
- 分布式系统通信的两种方式:直接远程调用 和 借助第三方 完成间接通信。
- 发送方称为生产者,接收方称为消费者。
- MQ的优势和劣势
优势:
1. 应用解耦
系统的耦合性越高,容错性越低,可维护性就越低。
2. 异步提速
提升用户体验和系统吞吐量。
3. 削峰填谷
提高系统的稳定性。
劣势:
二、RabbitMQ安装
基本指令
启动
service rabbitmq-server start
停止
service rabbitmq-server stop
重启
service rabbitmq-server restart开启web界面管理工具
rabbitmq-plugins enable rabbitmq_management
用户基本指令
查看用户
rabbitmqctl list_users新增用户
rabbitmqctl add_user Username Password
例如:
rabbitmqctl add_user root root设置权限
rabbitmqctl set_user_tags root administrator
三、web界面管理工具
1.添加一个用户:
用户角色
1、超级管理员(administrator)
可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。
2、监控者(monitoring)
可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)
3、策略制定者(policymaker)
可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。
4、普通管理者(management)
仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。
5、其他
无法登陆管理控制台,通常就是普通的生产者和消费者。
2.创建Virtual Hosts
3.设置权限
选择一个user。
在user界面可以看到,已添加权限。
四、RabbitMQ的五种模式
1. 简单模式
步骤:
1.创建工程(生产者和消费者)
2.分别添加依赖
3.编写生产生者发生消息
4.编写消费者接收消息
添加依赖
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.13.0</version>
</dependency>
</dependencies>
生产者代码
public class Producer_HelloWorld {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("120.79.155.127"); //默认值localhost
factory.setVirtualHost("sparks"); //设置虚拟机
factory.setUsername("root"); //设置用户名(默认guest)
factory.setPassword("****"); //设置密码
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.Channel
Channel channel = connection.createChannel();
//5.创建队列
channel.queueDeclare("hello_world",true,false,false,null);
//6.发送消息
String body = "hello rabbitMQ";
channel.basicPublish("","hello_world",null,body.getBytes());
//释放资源
channel.close();
connection.close();
消费者代码
public class Consumer_Hello {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
factory.setHost("120.79.155.127"); //默认值localhost
factory.setVirtualHost("/sparks"); //设置虚拟机
factory.setUsername("root"); //设置用户名(默认guest)
factory.setPassword("root"); //设置密码
//3.创建连接 Connection
Connection connection = factory.newConnection();
//4.Channel
Channel channel = connection.createChannel();
//5.创建队列
channel.queueDeclare("hello_world",true,false,false,null);
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("consumerTag:" + consumerTag);
System.out.println("envelope:" + envelope);
System.out.println("properties:" + properties);
System.out.println("body:" + body);
}
};
channel.basicConsume("hello_world",true,consumer);
消费者不需要关闭资源
2. 工作队列模式
相当于一个生产者将消息发送给多个消费者,多个消费者轮流从队列接收处理消息。
只需要创建两个消费者,分别对该队列接收数据。
3.发布订阅模式
生产者发送消息不再直接发送给队列,而是发送给交换机。
Exchange: 交换机。
一方面,接收生产者发送的消息,另一方面,指定如何处理消息。
Exchange有以下三种类型:
- Fanout : 广播,将消息交给所有绑定到交换机的队列。
- Direct: 定向,把消息交给符合指定 routing key 的队列。
- Topic: 通配符,把消息交给符合 routing pattern (路由模式) 的队列。
发布订阅模式用的是Fanout类型。
生产者代码:
//5.创建交换机
String exchangeName = "test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
//6.创建队列
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
// 参数: 1. 队列名称 2. 交换机名称 3. routingKey 路由键,绑定规则 fanout 为 "";
//8.发送消息
String body = "发布订阅模式开启";
channel.basicPublish(exchangeName,"",null,body.getBytes());
消费者只需要修改接收的队列名称即可。
4. Routing路由模式
Exchange 交换机类型: Direct
- 队列与交换机绑定时,要指定一个RoutingKey(路由key)。
- 消息的发送方在 向 Exchange 发送消息时,也必须指定消息的RoutingKey。
- Exchange 根据消息的 RoutingKey 进行判断,只有队列的 RoutingKey 与消息的 RoutingKey 完全一致,才会接收消息。
生产者代码:
//创建交换机
String exchangeName = "test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
//6.创建队列
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
channel.queueBind(queue1Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
// 参数: 1. 队列名称 2. 交换机名称 3. routingKey 路由键,绑定规则 fanout 为 "";
//8.发送消息
String body = "日志信息,Routing模式开启";
String error = "日志信息,Routing模式开启种出现错误";
channel.basicPublish(exchangeName,"info",null,body.getBytes());
channel.basicPublish(exchangeName,"error",null,error.getBytes());
消费者只需要修改接收消息的队列名称。
5. Topic通配符模式
-
*(星号) 可以完全代替一个词。
-
#(散列) 可以代替零或多个单词。
Exchange 交换机模式: Topic -
队列与交换机绑定时,要指定一个通配符。
-
消息的发送方在 向 Exchange 发送消息时,也必须指定消息的Routing Key。
-
Exchange 根据消息的 Routing Key 进行判断,只有队列的 通配符 与消息的 Routing Key 相匹配,队列才会接收消息。
生产者代码:
//5.创建交换机
String exchangeName = "test_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
//6.创建队列
// String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机 指定通配符
channel.queueBind(queue1Name,exchangeName,"#.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
channel.queueBind(queue2Name,exchangeName,"*.*");
// 参数: 1. 队列名称 2. 交换机名称 3. routingKey 路由键,绑定规则 fanout 为 "";
//8.发送消息
String body = "日志信息,Routing模式开启";
String error = "日志信息,Routing模式开启种出现错误";
channel.basicPublish(exchangeName,"order.info",null,body.getBytes());
channel.basicPublish(exchangeName,"sql.log.error",null,error.getBytes());
"#.error" 可以匹配 “sql.log.error” ,因为 # 可以代替零或多个单词。
五、Spring整合RabbitMQ
六、Springboot整合RabbitMQ
配置文件:application.yml
spring:
rabbitmq:
host: 120.79.155.127
port: 5672
username: root
password: ****
virtual-host: /sparks
生产生配置类:
- 1.配置交换机
- 2.配置队列
- 3.绑定交换机和队列
@Configuration
public class RabbitMQConfig {
public static final String EXCHANGE_NAME = "boot_topic_exchange";
public static final String QUEUE_NAME = "boot_queue";
//1.交换机
@Bean("bootExchange")
public Exchange bootExchange() {
return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
}
//2.Queue
@Bean("bootQueue")
public Queue bootQueue() {
return QueueBuilder.durable(QUEUE_NAME).build();
}
//3.队列和交换机绑定
@Bean
public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue,@Qualifier("bootExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("boot.#").noargs();
}
}
生产者代码测试:
@SpringBootTest
public class ProducerTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSend() {
rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.test","boot rabbit hello");
}
}
生产端直接注入RabbitTemplate完成消息发送。
消费端:
配置文件:
spring:
rabbitmq:
host: 120.79.155.127
port: 5672
username: root
password: ****
virtual-host: /sparks
@Component
public class RabbitMQListener {
@RabbitListener(queues = "boot_queue")
public void ListenerQueue(Message message) {
System.out.println(new String(message.getBody()));
}
}
消费端直接使用 @RabbitListener 完成消息接收。