前言
上节讲了缓存数据库redis的使用,在实际工作中,一般上在系统或者应用间通信或者进行异步通知(登录后发送短信或者邮件等)时,都会使用消息队列进行解决此业务场景的解耦问题。这章节讲解下消息队列RabbitMQ的集成和简单使用示例。
RabbitMQ介绍
RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
关于AMQP(摘自互联网):
AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
- 咳咳上午吧环境搭建好,现在咱们一起来搞代码。
不懂环境搭建的可以看我上一篇:https://blog.csdn.net/qq_30667039/article/details/87857388
在这补充一下AMQP
AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。
写代码之前还有一部重要的权限操作,这里是没有操作权限的
现在就看到有所有操作权限了,开始搞代码
第一种模式
SpringBoot整合RabbitMQ(Direct模式)
SpringBoot整合RabbitMQ非常简单!感觉SpringBoot真的极大简化了开发的搭建环境的时间…这样我们程序员就可以把更多的时间用在业务上了,下面开始搭建环境:
首先创建两个maven工程,这是为了模拟分布式应用系统中,两个应用之间互相交流的过程,一个发送者(Sender),一个接收者(Receiver)
根据spring 的老套路附上maven
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
附上yml配置文件 注意host不能写localhost,不然等着报错吧你。
rabbitmq:
host: 127.0.0.1
port: 15672
username: guest
password: guest
随后,配置Queue(消息队列).那注意由于采用的是Direct模式,需要在配置Queue的时候,指定一个键,使其和交换机绑定.
@Configuration
public class SenderConf {
@Bean
public Queue queue() {
return new Queue(“queue”);
}
}
下面我们使用AmqpTemplate去勾搭隔壁的小姐姐
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class HelloSender {
@Autowired
private AmqpTemplate template;
public void send() {
template.convertAndSend("queue","我是隔壁老罗~你好隔壁xx小姐");
}
}
再编写一个测试的的类,这样我们的发送端代码就编写完了
@Autowired
HelloSender helloSender;
@MyLog(“消息发送”)
@ApiOperation(value = “消息发送”,tags = “消息发送”)
@GetMapping(value = “sendmes”)
public void sendmes() {
helloSender.send();
}
接下来我们新建另一个监听项目,用来监听指定的Queue
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class HelloReceive {
@RabbitListener(queues="queue")
public void processC(String str) {
System.out.println("Receive:"+str);
}
}
我们下面来测试一下,8443成功撩到隔壁8442小姐姐,需要注意的地方,Direct模式相当于一对一模式,一个消息被发送者发送后,会被转发到一个绑定的消息队列中,然后被一个接收者接收!如果你想吧自己(对象)传过去,那么你就要先把自己给打包一下(序列化)过去。
第二种模式
SpringBoot整合RabbitMQ(Topic转发模式)
首先我们看发送端,我们需要配置队列Queue,再配置交换机(Exchange),再把队列按照相应的规则绑定到交换机上:
@Bean(name="messages")
public Queue queueMessages() {
return new Queue("topic.messages");
}
@Bean
public TopicExchange exchange() {
return new TopicExchange("exchange");
}
@Bean
Binding bindingExchangeMessage(@Qualifier("message") Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
Binding bindingExchangeMessages(@Qualifier("messages") Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");//*表示一个词,#表示零个或多个词
}
而在接收端,我们配置两个监听器,分别监听不同的队列:
@RabbitListener(queues="topic.message")
public void process1(String str) {
System.out.println("message:"+str);
}
@RabbitListener(queues="topic.messages")
public void process2(String str) {
System.out.println("messages:"+str);
}
方法的第一个参数是交换机名称,第二个参数是发送的key,第三个参数是内容,RabbitMQ将会根据第二个参数去寻找有没有匹配此规则的队列,如果有,则把消息给它,如果有不止一个,则把消息分发给匹配的队列(每个队列都有消息!),显然在我们的测试中,参数2匹配了两个队列,因此消息将会被发放到这两个队列中,而监听这两个队列的监听器都将收到消息!那么如果把参数2改为topic.messages呢?显然只会匹配到一个队列,那么process2方法对应的监听器收到消息!
第三种模式
SpringBoot整合RabbitMQ(Fanout Exchange形式)Fanout Exchange形式又叫广播形式,因此我们发送到路由器的消息会使得绑定到该路由器的每一个Queue接收到消息,这个时候就算指定了Key,或者规则(即上文中convertAndSend方法的参数2),也会被忽略!那么直接上代码,发送端配置如下
@Bean(name=“Amessage”)
public Queue AMessage() {
return new Queue(“fanout.A”);
}
@Bean(name="Bmessage")
public Queue BMessage() {
return new Queue("fanout.B");
}
@Bean(name="Cmessage")
public Queue CMessage() {
return new Queue("fanout.C");
}
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");//配置广播路由器
}
@Bean
Binding bindingExchangeA(@Qualifier("Amessage") Queue AMessage,FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(@Qualifier("Bmessage") Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeC(@Qualifier("Cmessage") Queue CMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(CMessage).to(fanoutExchange);
}
测试下广播模式