什么是RabbitMQ?
RabbitMQ是一个消息中间件,是一个实现了AMQP(高级消息队列协议)的开源消息代理软件,同类的产品还有kafka,rocketMQ,但是目前springcloud只集成了RabbitMQ和kafka,他的作用就是实现系统之间消息传递的解耦,对一些实时性要求不是很高的服务或者并发很高的系统来说是一个不错的选择,同时因为RabbitMQ是以AMQP协议实现的,所以支持多操作系统,多编程语言,先来理解一下RabbitMQ的几个概念:
broker:消息队列服务器实体,它是一个中间件应用,负责接收消息生产者的消息,然后将消息发送给消息消费者或者别的broker;
Exchange:消息交换机,这是消息第一个到达的地方,消息通过他指定的路由规则,发送给不同的消息队列;
Queue:消息队列,消息通过发送和Exchange路由后最终到达的地方,理论上消息到达Queue后就是等待消费的状态,一个消息最终会发送给一个或者多个Queue;
Binding:绑定,将Exchange和Queue按照路由规则绑定起来,也就是建立Exchange和Queue的虚拟连接;
Routing key:路由关键字,Exchange根据这个路由关键字进行投递;
Virtual Host:虚拟主机,一个Broker可能包含多个虚拟主机;
Connection:连接,代表生产者、消费者、Broker之间的物理连接;
Channel:消息通道,用于连接生产者和消费者的逻辑结构。每个连接里面可能有多个Channel,每个Channel代表一个会话;
Producer:消息生产者;
Consumer:消息消费者;
消息投递到队列的整个过程:
1、客户端连接到消息队列服务器Broker,建立一个Channel连接;
2、客户端声明一个Exchange,设置其属性;
3、客户端声明一个Queue,设置其属性;
4、客户端声明一个Routing key,binding Exchange和Queue;
5、客户端发送一条消息,Exchange接收到消息后,根据key解析路由到相应的队列;
Exchange也有集中类型:
1、Direct交换机:完全根据key投递,比如设置了Routing key等于abc,那么客户端必须发送key=abc才会被投递到队列;
2、topic交换机:根据key进行模糊匹配后投递,可以使用符合#匹配一个或者多个词,*只能匹配一个次;
3、Fanout:无需配置关键字Key,它采用广播室,一个消息进来,投递给所有与该Exchange绑定的消息队列;
RabbitMQ也支持消息的持久化,就会将数据写在磁盘上,默认为了安全考虑,建议消息持久化;
1、Exchange持久化,客户端配置时durable>=1;
2、Queue持久化,客户端配置时durable>=1;
3、消息持久化,在投递时设定delivery_mode>=2;
二、安全与启动:
略;
三:springCloud整合RabbitMQ最简单的用法:
1、引入maven依赖:
<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> </dependency>
2、在application.properties中设置RabbitMQ的配置信息:
spring.application.name=rabbitmq-hello spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest
3、建立一个消息的生产者:
@Component public class Sender { @Autowired private AmqpTemplate rabbitmqTemplate; public void send(){ String content = "hello" + new Date(); System.out.println("Sender:" +content); this.rabbitmqTemplate.convertAndSend("hello", content); } }
生产者Send会像Queue=hello发送一条消息;
4、建议一个消息的消费者:
@Component @RabbitListener(queues = "hello") public class Receiver { @RabbitHandler public void process(String hello){ System.out.println("Receiver:" + hello); } }@RabbitListener表示对队列hello进行监听,@RabbitHandler指定对消息的处理方法;
5、创建一个RabbitMQ的配置文件:
@Configuration public class RabbitConfig { @Bean public Queue helloQueue(){ return new Queue("hello"); } }
这个配置文件只要是建立一个消息队列hello;
6、创建应用主类和单元测试类:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) public class HelloApplicationTests { @Autowired private Sender sender; @Test public void hello(){ sender.send(); } }
2、Direct交换机和topic交换机的用法:
@Bean public Queue queueMessage(){ return new Queue("topic_message"); } @Bean public Queue queueMessages(){ return new Queue("topic_messages"); }
@Bean TopicExchange exchange(){ return new TopicExchange("exchage"); } //Direct交换机的绑定 @Bean Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange){ return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message"); } //Topic交换机的绑定 @Bean Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange){ return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#"); }
//消息生产者
public void send(){ String content = "hello" + new Date(); this.rabbitmqTemplate.convertAndSend("exchage","topic.message","topic_message"); this.rabbitmqTemplate.convertAndSend("exchage","topic.messages","topic_messages"); }
第一个参数是exchange,第二个参数是routingkey,第三个参数是发送的消息message
消息消费者:
@Component @RabbitListener(queues = "topic_message") public class Receiver1 { @RabbitHandler public void process(String hello){ System.out.println("Receiver1:" + hello); } }
@Component @RabbitListener(queues = "topic_messages") public class Receiver2 { @RabbitHandler public void process(String hello){ System.out.println("Receiver2:" + hello); } }
3.广播交换机的用法:
就是banding的时候少了routingkey的绑定:
@Bean Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange){ return BindingBuilder.bind(queueMessage).to(exchange); }
然后发送数据的时候和RoutingKey没有关系,所以关键字可填可不填;