之前写过一篇关于RabbitMQ在linux环境的安装,这篇文章分享一下RabbitMQ的工作模型和在java中的使用。
Rabbit官网:http://www.rabbitmq.com/
RabbitMQ的特性:
- 可靠性:提供了消息确认机制
- 灵活的路由:内部提供交换机,通过交换机灵活的路由到队列
- 消息集群:支持集群部署
- 可用性:可以使用镜像队列来保证可用性
- 跨语言,跨平台:提供多种语言客户端,支持其他语言使用
- 插件机制:支持添加插件
- 管理界面
RabbitMQ使用的协议:
AMQP协议(Advancde Message Queuing Protocol),一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的开发标准,为面向消息的中间件而设计。基于此协议的客户端与小小中间件可传递消息,并不受客户端/中间件产品、不同的开发语言等条件的限制。跨语言,跨系统,跨平台。
RabbitMQ的工作模型:
RabbitMQ术语介绍:
消息生产者:就是用来发送消息的
路由关键字:交换机根据路由关键字把消息放入到相应的绑定队列中去
交换机:交换机就是生产者与队列之间沟通的桥梁
绑定关键字:绑定交换机,上面讲到了交换机会根据路由关键字把消息发送到响应的绑定队列中去,怎么去执行呢?就是会拿路由关键字和绑定关键字匹配,匹配成功就发送。
队列:队列就是消息的载体
主机:就是RabbitMQ服务器
虚拟机:一个RabbitMQ服务器可以创建多个虚拟机,一个虚拟机里可以有多个交换机和多个队列
connection:是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑
channel:Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等
消息消费者:用来消费消息
RabbitMQ基本使用:
本文直接使用SpringBoot来进行开发.
消息消费者:
项目结构:
添加pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
添加连接配置 application.properties
spring.application.name=spring-boot-rabbitmq
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
创建配置类:RabbitConfig
在这里创建了三种类型的交换机,四个队列。稍后会介绍交换机类型。
package com.zbb.rabbitmq_consumer.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 配置类,需要使用configuration注解
*/
@Configuration
public class RabbitConfig {
//定义三个交换机
/**
* 直连交换机
* @return
*/
@Bean
public DirectExchange directExchange(){
return new DirectExchange("DIRECT_EXCHANGE");
}
/**
* 主题交换机
* @return
*/
@Bean
public TopicExchange topicExchange(){
return new TopicExchange("TOPIC_EXCHANGE");
}
/**
* 广播交换机
* @return
*/
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("FANOUT_EXCHANGE");
}
//定义四个队列
@Bean
public Queue firsQueue(){
return new Queue("FIST_QUEUE");
}
@Bean
public Queue secondQueue(){
return new Queue("SECOND_QUEUE");
}
@Bean
public Queue thirdQueue(){
return new Queue("THIRD_QUEUE");
}
@Bean
public Queue fourthQueue(){
return new Queue("FOURTH_QUEUE");
}
//定义四个绑定关系
@Bean
public Binding bindFirst(@Qualifier("firsQueue") Queue queue,
@Qualifier("directExchange") DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with("zbb.test");
}
@Bean
public Binding bindSecond(@Qualifier("secondQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("*.zbb.*");
}
@Bean
public Binding bindThird(@Qualifier("thirdQueue") Queue queue,
@Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queue).to(fanoutExchange);
}
@Bean
public Binding bindFourth(@Qualifier("fourthQueue") Queue queue,
@Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queue).to(fanoutExchange);
}
}
创建消费者,四个,分别监听4个队列
1、FirstConsumer
package com.zbb.rabbitmq_consumer.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "FIST_QUEUE")
public class FirstConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("消费者一收到消息:"+msg);
}
}
2、SecondConsumer
package com.zbb.rabbitmq_consumer.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "SECOND_QUEUE")
public class SecondConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("消费者二收到消息:"+msg);
}
}
3、ThirdConsumer
package com.zbb.rabbitmq_consumer.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "THIRD_QUEUE")
public class ThirdConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("消费者三收到消息:"+msg);
}
}
4、FourthConsumer
package com.zbb.rabbitmq_consumer.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@RabbitListener(queues = "FOURTH_QUEUE")
public class FourthConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("消费者四收到消息:"+msg);
}
}
消息生产者:
引入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
创建生产者类,给三个交换机发送消息
package com.zbb.rabbitmq_producer.producer;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyProducer {
@Autowired
RabbitTemplate rabbitTemplate;
public void send(){
//直连
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "zbb.test",
"this is a direct msg");
//主题
rabbitTemplate.convertAndSend("TOPIC_EXCHANGE","kaifa.zbb.IT",
"this is a Topic msg");
//广播
rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "",
"this is a fanout msg");
}
}
修改测试类:
package com.zbb.rabbitmq_producer;
import com.zbb.rabbitmq_producer.producer.MyProducer;
import org.junit.Test;
import org.junit.runner.RunWith;
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 RabbitmqProducerApplicationTests {
@Autowired
MyProducer myProducer;
@Test
public void contextLoads() {
myProducer.send();
}
}
我们先启动消息生产者,打开管理界面可以看到四个队列里都有一条消息堆积
现在去启动消息消费者之后会发现控制台打印出消息,并且管理界面发生改变:
这个就是RabbitMQ在java中的简单使用,具体在项目中的使用需要结合业务来进行消息的收发。
下面将介绍一下RabbitMQ中一个重要的东西:交换机Exchange
这里只介绍三种主要的交换机。
Direct Exchange 直连交换机
直连类型的交换机与一个队列绑定时,需要指定一个明确的绑定关键字(binding key)。
路由规则:发送消息到直连类型的交换机时,只有路由关键字(routing key)跟绑定关键字(binding key)完全匹配时,绑定的队列才能收到消息。
队列:
@Bean
public Queue firsQueue(){
return new Queue("FIST_QUEUE");
}
交换机:
@Bean
public DirectExchange directExchange(){
return new DirectExchange("DIRECT_EXCHANGE");
}
绑定:
@Bean
public Binding bindFirst(@Qualifier("firsQueue") Queue queue,
@Qualifier("directExchange") DirectExchange directExchange){
return BindingBuilder.bind(queue).to(directExchange).with("zbb.test");
}
发送消息:
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "zbb.test",
"this is a direct msg");
Topic Exchange 主题交换机
定义:主题类型的交换机与一个队列绑定时,可以指定按模式匹配的routing key。
通配符有两个,*代表匹配一个单词。#代表匹配零个或者多个单词。单词与单词之间用 . 隔开。
路由规则:发送消息到主题类型的交换机时,routing key符合binding key的模式时,绑定的队列才能收到消息
队列:
@Bean
public Queue secondQueue(){
return new Queue("SECOND_QUEUE");
}
交换机:
@Bean
public TopicExchange topicExchange(){
return new TopicExchange("TOPIC_EXCHANGE");
}
绑定:
@Bean
public Binding bindSecond(@Qualifier("secondQueue") Queue queue,
@Qualifier("topicExchange") TopicExchange topicExchange) {
return BindingBuilder.bind(queue).to(topicExchange).with("*.zbb.*");
}
发送消息:
//主题
rabbitTemplate.convertAndSend("TOPIC_EXCHANGE","kaifa.zbb.IT",
"this is a Topic msg");
Fanout Exchange 广播交换机,绑定两个队列thirdQueue fourthQueue
定义:广播类型的交换机与一个队列绑定时,不需要指定binding key。
路由规则:当消息发送到广播类型的交换机时,不需要指定routing key,所有与之绑定的队列都能收到消息。
队列:
@Bean
public Queue thirdQueue(){
return new Queue("THIRD_QUEUE");
}
@Bean
public Queue fourthQueue(){
return new Queue("FOURTH_QUEUE");
}
交换机:
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("FANOUT_EXCHANGE");
}
发送消息:
//广播
rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "",
"this is a fanout msg");