RabbitMQ学习(一)

前言:

 

一、    认识RabbitMQ

二、    Spring boot + RabbitMQ(初体验)

三、    Spring boot 整合RabbitMQ实现三种消息传递方式

四、    RabbitMQ高级

五、    RPC-RabbitMQ的使用


一、 认识RabbitMQ(搬运)

参考:

http://blog.csdn.net/anzhsoft/article/details/19563091  

http://blog.csdn.net/column/details/rabbitmq.html 

http://blog.csdn.net/dandanzmc/article/details/52244529


|简介

        RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现。AMQP 的出现其实也是应了广大人民群众的需求,虽然在同步消息通讯的世界里有很多公开标准(如 COBAR的 IIOP ,或者是SOAP 等),但是在异步消息处理中却不是这样,只有大企业有一些商业实现(如微软的 MSMQ ,IBM 的 Websphere MQ 等),因此,在 2006 年的 6 月,Cisco 、Redhat、iMatix 等联合制定了AMQP 的公开标准。

   RabbitMQ是由RabbitMQ Technologies Ltd开发并且提供商业支持的。该公司在2010年4月被SpringSource(VMWare的一个部门)收购。在2013年5月被并入Pivotal。其实VMWare,Pivotal和EMC本质上是一家的。不同的是VMWare是独立上市子公司,而Pivotal是整合了EMC的某些资源,现在并没有上市。

   RabbitMQ的官网是http://www.rabbitmq.com

 

|应用场景

RabbitMQ,或者说AMQP解决了什么问题,或者说它的应用场景是什么?

    对于一个大型的软件系统来说,它会有很多的组件或者说模块或者说子系统或者(subsystemor Component or submodule)。那么这些模块的如何通信?这和传统的IPC有很大的区别。传统的IPC很多都是在单一系统上的,模块耦合性很大,不适合扩展(Scalability);如果使用socket那么不同的模块的确可以部署到不同的机器上,但是还是有很多问题需要解决。比如:

 1)信息的发送者和接收者如何维持这个连接,如果一方的连接中断,这期间的数据如何方式丢失?

 2)如何降低发送者和接收者的耦合度?

 3)如何让Priority高的接收者先接到数据?

 4)如何做到load balance?有效均衡接收者的负载?

 5)如何有效的将数据发送到相关的接收者?也就是说将接收者subscribe不同的数据,如何做有效的filter。

 6)如何做到可扩展,甚至将这个通信模块发到cluster上?

 7)如何保证接收者接收到了完整,正确的数据?

  AMDQ协议解决了以上的问题,而RabbitMQ实现了AMQP。

 

|架构

系统架构图版权属于sunjun041640

 

RabbitMQ Server: 也叫broker server,它不是运送食物的卡车,而是一种传输服务。原话是RabbitMQisn’t afood truck, it’s a delivery service. 他的角色就是维护一条从Producer到Consumer的路线,保证数据能够按照指定的方式进行传输。但是这个保证也不是100%的保证,但是对于普通的应用来说这已经足够了。当然对于商业系统来说,可以再做一层数据一致性的guard,就可以彻底保证系统的一致性了。

    Client A & B: 也叫Producer,数据的发送方。createmessages and publish (send) them to a broker server (RabbitMQ).一个Message有两个部分:payload(有效载荷)和label(标签)。payload顾名思义就是传输的数据。label是exchange的名字或者说是一个tag,它描述了payload,而且RabbitMQ也是通过这个label来决定把这个Message发给哪个Consumer。AMQP仅仅描述了label,而RabbitMQ决定了如何使用这个label的规则。

    Client 1,2,3:也叫Consumer,数据的接收方。Consumersattach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一个有名字的邮箱。当有Message到达某个邮箱后,RabbitMQ把它发送给它的某个订阅者即Consumer。当然可能会把同一个Message发送给很多的Consumer。在这个Message中,只有payload,label已经被删掉了。对于Consumer来说,它是不知道谁发送的这个信息的。就是协议本身不支持。但是当然了如果Producer发送的payload包含了Producer的信息就另当别论了。

    对于一个数据从Producer到Consumer的正确传递,还有三个概念需要明确:exchanges, queuesand bindings。

        Exchanges are whereproducers publish their messages.

        Queues are where the messages end up and are received by consumers

        Bindings are how the messages get routed from the exchange toparticular queues.

   还有几个概念是上述图中没有标明的,那就是Connection(连接),Channel(通道,频道)。

   Connection: 就是一个TCP的连接。Producer和Consumer都是通过TCP连接到RabbitMQ Server的。以后我们可以看到,程序的起始处就是建立这个TCP连接。

   Channels: 虚拟连接。它建立在上述的TCP连接中。数据流动都是在Channel中进行的。也就是说,一般情况是程序起始建立TCP连接,第二步就是建立这个Channel。

    那么,为什么使用Channel,而不是直接使用TCP连接?

   对于OS来说,建立和关闭TCP连接是有代价的,频繁的建立关闭TCP连接对于系统的性能有很大的影响,而且TCP的连接数也有限制,这也限制了系统处理高并发的能力。但是,在TCP连接中建立Channel是没有上述代价的。对于Producer或者Consumer来说,可以并发的使用多个Channel进行Publish或者Receive。有实验表明,1s的数据可以Publish10K的数据包。当然对于不同的硬件环境,不同的数据包大小这个数据肯定不一样,但是我只想说明,对于普通的Consumer或者Producer来说,这已经足够了。如果不够用,你考虑的应该是如何细化split你的设计。

 

|进一步

      |使用ack确认Message的正确传递

默认情况下,如果Message 已经被某个Consumer正确的接收到了,那么该Message就会被从queue中移除。当然也可以让同一个Message发送到很多的Consumer。

   如果一个queue没被任何的ConsumerSubscribe(订阅),那么,如果这个queue有数据到达,那么这个数据会被cache,不会被丢弃。当有Consumer时,这个数据会被立即发送到这个Consumer,这个数据被Consumer正确收到时,这个数据就被从queue中删除。

    那么什么是正确收到呢?通过ack。每个Message都要被acknowledged(确认,ack)。我们可以显示的在程序中去ack,也可以自动的ack。如果有数据没有被ack,那么:

    RabbitMQ Server会把这个信息发送到下一个Consumer

   如果这个app有bug,忘记了ack,那么RabbitMQ Server不会再发送数据给它,因为Server认为这个Consumer处理能力有限。

  而且ack的机制可以起到限流的作用(Benefitto throttling):在Consumer处理完成数据后发送ack,甚至在额外的延时后发送ack,将有效的balance Consumer的load。

  当然对于实际的例子,比如我们可能会对某些数据进行merge,比如merge 4s内的数据,然后sleep 4s后再获取数据。特别是在监听系统的state,我们不希望所有的state实时的传递上去,而是希望有一定的延时。这样可以减少某些IO,而且终端用户也不会感觉到。

 

      |Reject amessage

有两种方式,第一种的Reject可以让RabbitMQ Server将该Message 发送到下一个Consumer。第二种是从queue中立即删除该Message。

 

|Creating a queue

Consumer和Procuder都可以通过 queue.declare 创建queue。对于某个Channel来说,Consumer不能declare一个queue,却订阅其他的queue。当然也可以创建私有的queue。这样只有app本身才可以使用这个queue。queue也可以自动删除,被标为auto-delete的queue在最后一个Consumer unsubscribe后就会被自动删除。那么如果是创建一个已经存在的queue呢?那么不会有任何的影响。需要注意的是没有任何的影响,也就是说第二次创建如果参数和第一次不一样,那么该操作虽然成功,但是queue的属性并不会被修改。

    那么谁应该负责创建这个queue呢?是Consumer,还是Producer?

如果queue不存在,当然Consumer不会得到任何的Message。但是如果queue不存在,那么Producer Publish的Message会被丢弃。所以,还是为了数据不丢失,Consumer和Producer都tryto create the queue!反正不管怎么样,这个接口都不会出问题。

  queue对load balance的处理是完美的。对于多个Consumer来说,RabbitMQ 使用循环的方式(round-robin)的方式均衡的发送给不同的Consumer。

 

      |Exchanges

 从架构图可以看出,Procuder Publish的Message进入了Exchange。接着通过“routing keys”, RabbitMQ会找到应该把这个Message放到哪个queue里。queue也是通过这个routing keys来做的绑定。

    有三种类型的Exchanges:direct,fanout,topic。 每个实现了不同的路由算法(routing algorithm)。

·        Direct exchange:如果 routing key 匹配, 那么Message就会被传递到相应的queue中。其实在queue创建时,它会自动的以queue的名字作为routing key来绑定那个exchange。

·        Fanout exchange:会向响应的queue广播。

·        Topic exchange:对key进行模式匹配,比如ab*可以传递到所有ab*的queue。

 

      |Virtual hosts

每个virtual host本质上都是一个RabbitMQ Server,拥有它自己的queue,exchagne,和bingsrule等等。这保证了你可以在多个不同的application中使用RabbitMQ


二、Spring boot+ RabbitMQ(初体验)

idea

maven3.x

 

1、安装rabbitMQ

windws下

      https://www.cnblogs.com/ericli-ericli/p/5902270.html(安装教程)

      http://www.rabbitmq.com/download.html 下载相应系统的版本

下载后即可安装,安装过程可能需要前置安装Erlang,根据提示安装即可。

按照教程即可安装,访问默认的地址http://localhost:15672/

这里将一些比较重要的地方进行重点描述,加深印象(以下为搬运)

rabbitmq用户角色可分为五类:超级管理员, 监控者, 策略制定者, 普通管理者以及其他

 (1) 超级管理员(administrator)

可登陆管理控制台(启用management plugin的情况下),可查看所有的信息,并且可以对用户,策略(policy)进行操作。

(2) 监控者(monitoring)

可登陆管理控制台(启用management plugin的情况下),同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等) 

(3) 策略制定者(policymaker)

可登陆管理控制台(启用management plugin的情况下), 同时可以对policy进行管理。

(4) 普通管理者(management)

仅可登陆管理控制台(启用management plugin的情况下),无法看到节点信息,也无法对策略进行管理。

(5) 其他的:

无法登陆管理控制台,通常就是普通的生产者和消费者。

 

相关命令:

查看已用户及用户的角色:rabbitmqctl.bat list_users

       新增用户:rabbitmqctl.bat add_user username password

       修改用户角色:rabbitmqctl.bat set_user_tags username administrator

多角色授权:rabbitmqctl.bat  set_user_tags  username tag1 tag2 ...

       修改密码:rabbitmqctl change_password userName newPassword

       删除用户:rabbitmqctl.bat delete_user username

 

权限设置:

用户权限指的是用户对exchange,queue的操作权限,包括配置权限,读写权限。我们配置权限会影响到exchange、queue的声明和删除。读写权限影响到从queue里取消息、向exchange发送消息以及queue和exchange的绑定(binding)操作。

权限相关命令为:

(1) 设置用户权限

rabbitmqctl  set_permissions  -p  VHostPath  User  ConfP  WriteP  ReadP

(2) 查看(指定hostpath)所有用户的权限信息

rabbitmqctl  list_permissions  [-p  VHostPath]

(3) 查看指定用户的权限信息

rabbitmqctl  list_user_permissions  User

(4)  清除用户的权限信息

rabbitmqctl  clear_permissions  [-p VHostPath]  User

 

Linux(centOS7暂未测试,后续补充)

2、spring boot整合rabbitMQ

Maven依赖

 

配置yml文件

参考:

http://blog.csdn.net/a286352250/article/details/53158667

http://blog.csdn.net/jek123456/article/details/74120190

 

测试一:

 

创建消息接收者

import org.springframework.stereotype.Component;
import java.util.concurrent.CountDownLatch;
/**
 * author : jimmyLJM on 2017-11-24
 *
创建消息接收者
 
*/
@Component
public class MyReciver {
   
/*  自动注入CountDownLatch类告诉发送者消息已经收到了即用来act时候使用
       
不需要在应用程序中具体实现它,只需要latch.countDown()就行了
     */
   
private CountDownLatch latch = new CountDownLatch(1);

   
public void receiveMessage(String message) {
       
System.out.println("TestRecive <" + message + ">");
       
latch.countDown();
    }
   
public CountDownLatch getLatch() {
       
return latch;
    }
}

创建消息生产者

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 *
 * author : jimmyLJM on 2017-11-24
 */
@Component
public class MySender {
   
// 定义一个消息队列的名字用于测试使用
   
final static String queueName = "spring-boot";

   
// 创建Queue
   
@Bean
   
Queue queue() {
       
return new Queue(queueName, false);
    }

   
// 定义一个topic交换器
   
@Bean
   
TopicExchange exchange() {
       
return new TopicExchange("spring-boot-exchange");
    }

   
// 将消息队列queueexchange绑定
   
@Bean
   
Binding binding(Queue queue, TopicExchange exchange) {
       
return BindingBuilder.bind(queue).to(exchange).with(queueName);
    }

   
// 创建消息监听的容器
   
@Bean
   
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
                                            
MessageListenerAdapter listenerAdapter) {
       
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
       
container.setConnectionFactory(connectionFactory);
       
container.setQueueNames(queueName);
       
container.setMessageListener(listenerAdapter);
       
return container;
    }

   
@Bean
   
MessageListenerAdapter listenerAdapter(MyReciver receiver) {
        
return new MessageListenerAdapter(receiver, "receiveMessage");
    }

}

 

测试类:

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 *  RabbitMQ
测试类
 
* author : jimmyLJM on 2017-11-24
 *
 *
项目服务启动的时候就去加载一些数据或做一些事情这样的需求
 
* 实现接口 CommandLineRunner 来实现重写run方法
 
*/
@Component
public class TestMQ implements CommandLineRunner{

   
private final RabbitTemplate rabbitTemplate;
   
private final MyReciver receiver;
   
private final ConfigurableApplicationContext context;

   
public TestMQ(MyReciver receiver, RabbitTemplate rabbitTemplate,
                  
ConfigurableApplicationContext context) {
       
this.receiver = receiver;
       
this.rabbitTemplate = rabbitTemplate;
       
this.context = context;
    }
   
@Override
   
public void run(String... args) throws Exception {
       
System.out.println("Sending message...");
       
rabbitTemplate.convertAndSend("spring-boot", "Hello from RabbitMQ!");
       
receiver.getLatch().await(10000, TimeUnit.MILLISECONDS);
       
context.close();
    }

}

启动spring boot后报错,错误提示如下:

2017-11-24 10:23:22.802  INFO 8756 --- [  restartedMain] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase -2147482648

2017-11-24 10:23:22.802  INFO 8756 --- [  restartedMain] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647

2017-11-24 10:23:22.802  INFO 8756 --- [  restartedMain] d.s.w.p.DocumentationPluginsBootstrapper : Context refreshed

2017-11-24 10:23:22.819  INFO 8756 --- [  restartedMain] d.s.w.p.DocumentationPluginsBootstrapper : Found 1 custom documentation plugin(s)

2017-11-24 10:23:22.829  INFO 8756 --- [  restartedMain] s.d.s.w.s.ApiListingReferenceScanner     : Scanning for api listing references

2017-11-24 10:23:22.938  INFO 8756 --- [  restartedMain] .d.s.w.r.o.CachingOperationNameGenerator : Generating unique operation named: indexUsingGET_1

2017-11-24 10:23:23.078  INFO 8756 --- [    container-1] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#188cffa:0/SimpleConnection@f06f26 [delegate=amqp://guest@127.0.0.1:5672/, localPort= 62367]

2017-11-24 10:23:23.132  WARN 8756 --- [    container-1] o.s.a.r.listener.BlockingQueueConsumer   : Failed to declare queue:spring-boot

2017-11-24 10:23:23.138  WARN 8756 --- [    container-1] o.s.a.r.listener.BlockingQueueConsumer   : Queue declaration failed; retries left=3

 

org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[spring-boot]

         at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:643) ~[spring-rabbit-1.7.3.RELEASE.jar:na]

         at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:542) ~[spring-rabbit-1.7.3.RELEASE.jar:na]

         at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1389) [spring-rabbit-1.7.3.RELEASE.jar:na]

         at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]

Caused by: java.io.IOException: null

         at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:105) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:101) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:123) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:992) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:50) ~[amqp-client-4.0.2.jar:4.0.2]

         at org.springframework.amqp.rabbit.support.PublisherCallbackChannelImpl.queueDeclarePassive(PublisherCallbackChannelImpl.java:335) ~[spring-rabbit-1.7.3.RELEASE.jar:na]

         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]

         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]

         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_111]

         at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_111]

         at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:955) ~[spring-rabbit-1.7.3.RELEASE.jar:na]

         at com.sun.proxy.$Proxy125.queueDeclarePassive(Unknown Source) ~[na:na]

         at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:622) ~[spring-rabbit-1.7.3.RELEASE.jar:na]

         ... 3 common frames omitted

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'spring-boot' in vhost '/', class-id=50, method-id=10)

         at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:32) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:366) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:229) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:117) ~[amqp-client-4.0.2.jar:4.0.2]

         ... 13 common frames omitted

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'spring-boot' in vhost '/', class-id=50, method-id=10)

         at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:505) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:336) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:143) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:90) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:634) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47) ~[amqp-client-4.0.2.jar:4.0.2]

         at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:572) ~[amqp-client-4.0.2.jar:4.0.2]

         ... 1 common frames omitted

 

 

 

进入rabbitMQ控制台http://localhost:15672/#/

在如图的地方添加名字(queue)然后点【击Add queue】按钮

重新启动spring boot后可以看到控制台显示如下:

 

测试二

创建消息接收者

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 *
消息队列接收类
 
* author : jimmyLJM on 2017-11-24
 *
使用 RabbitListener 注解使接收者监听名称为helloqueue
 *     RabbitHandler
对接收到的消息进行处理
 
*/
@Component
@RabbitListener
(queues = "hello")
public class DemoRabbitMqReceiver {
   
@RabbitHandler
   
public void process(String content) {
       
System.out.println("DemoRabbitMqReceiver : " + content);
    }

 

创建消息发送者:

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * author : jimmyLJM on 2017-11-24
 */
@Component
public class DemoRabbitMqSender {
   
@Autowired
   
private AmqpTemplate rabbitTemplate;

   
public void send(String content) {
       
System.out.println("Sender : " + content);
       
this.rabbitTemplate.convertAndSend("hello", content);
    }
}

 

测试类:

import com.jimmy.springBootDemo.MQ.DemoRabbitMqSender;
import com.jimmy.springBootDemo.util.ResultUtil;
import com.jimmy.springBootDemo.vo.Result;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

/**
 * author : jimmyLJM on 2017-11-24
 *
测试Rabbit MQ
 */
@RestController
@RequestMapping
(value="/rabbitmq")
public class DemoRabbitMqController {
   
@Autowired
   
private DemoRabbitMqSender demoRabbitMqSender;
   
/**
     *
发送测试消息队列
    
*/
   
@ApiOperation(value="发送测试消息队列", notes="addEntity")
   
@RequestMapping(value = "/addRabbitMq", method = RequestMethod.GET)
   
public Result addEntity(HttpSession httpSession) {
       
demoRabbitMqSender.send("rabbitMQ demo test...");
       
return ResultUtil.success();
    }
}

 

使用swagger测试

测试后控制台打印:

 

比较测试一(A)和测试二(B):

A :使用RabbitTemplate的convertAndSend()方法来进行传递消息

     通过消息监听容器SimpleMessageListenerContainer加载监听适配器

MessageListenerAdapter(绑定接收者的对应方法),设置监听的queue

使用BindingBuilder将queue和exchange绑定

 

B:借助注解来使消息接受者主动监听生产者发送的消息

@RabbitListener

@RabbitHandler

消息生产者借用AmqpTemplate类注入的实例(RabbitTemplate)来发送消息

测试的时候直接注入生产者调用send方法将消息发送出去

 

AmqpTemplate和RabbitTemplate之间存在以下关系

 

这样我们就实现了spring boot调用 RabbitMQ实现了消息的发送和接受。






阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页