springboot整合rabbitMQ,以及rabbitMQ的部分功能介绍

如果想看源码,直接跳到文章末尾。
如果想看源码,直接跳到文章末尾。
如果想看源码,直接跳到文章末尾。


rabbitMQ介绍

RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端。——来自百度百科,说白了就是消息中间件

1、那么消息中间件能干吗?

  1. 解耦:降低各个子系统之间的依赖度。
  2. 存储:临时存储信息(数据包)。
  3. 削峰:避免因为访问量过大而导致系统崩溃。
  4. 顺序:保证消息之间的传递顺序。
  5. 延处:延迟处理消息,系统可能因为不想立即处理消息,可以把这部分的消息放在消息中间件中。

2、基本概念

  1. 消息服务的两个概念,消息代理和消息目的地。其中消息代理就是消息中间件服务器,消息目的地指消息中间件将消息要发送的地点。
  2. 消息队列的两种实现:
    1)point to point;点对点发送
    2)publish/subscribe:发布/订阅——自行百度,这个不用说了吧
  3. message:要保存在消息队列中的消息,包括消息头和消息体,其中消息体不透明,消息头包含一些列消息属性,主要有三个,分别是routing-key(路由键,指定消息传送规则),priority(指定消息优先级)和delivery-mode(指定该消息可能需要持久存储)
  4. publisher:发布者,指定向消息服务器发送消息的客户端
  5. exchange:交换器,用来接收publisher发送的消息,并将此消息的routing-key根据交换规则放到指定的消息队列中,一个交换机可以链接多个消息队列或者多个交换机。消息队列接收消息是根据交换规则来决定的,交换规则总共有四种,分别如下:
  • direct(直接发送):也就是点对点式发送,exchange直接指定要接收消息的队列。
  • topic(主题形式发送):根据一定的规则进行匹配要接收的消息队列。例如*.news 可以匹配名称为1111.news,222.news的消息队列。news.# 可以匹配news.ppp,news.xxx消息队列。其中*表示一个单词的匹配,而#号表示多个单词的匹配。
  • fanout(扩展形式发送):表示所有交换机下的所有消息队列都接收消息。
  • headers(头信息式发送):将信息写在消息头中,交换规则不在由routing-key来指定,而是根据message header消息头信息来指定。
  1. queue:消息队列,用来保存publisher经过exchange路由选择后的消息。
  2. binding:绑定,就是来说明exchange和queue之间关系的表,通过routing-key来实现。(这里的绑定不代表交换规则发送,这里的绑定指的是这个queue到底属于那些个exchange。)
  3. connection:一个TCP链接
  4. channel:信道,用来缓解多个tcp链接所带来的资源消耗问题。OS中TCP链接是很费资源的,信道的作用就是复用一个TCP链接,减小资源的浪费。
  5. consumer:消费者,指从消息队列中取出消息的实体。
  6. virtual host:指一组交换机、消息队列和相关对象,相当于一个独立的服务器。
  7. broker:中间件,服务器实体。

3、rabbitMQ运行机制

在这里插入图片描述
生产者和broker之间构建一个TCP链接,每个生产者将消息以信道的方式传递给broker,broker再把消息交给exchange,exchange然后根据消息的routing-key和交换规则,来选择合适的queue进行传递。消费者可以和broker建立一个TCP链接,然后根据信道的方式从消息队列中取得消息。


OK,原理解释清楚了,开始spring boot和rabbitMQ得整合。


spring boot整合rabbitMQ

1、spring boot官方文档

14.2. AMQP
The Advanced Message Queuing Protocol (AMQP) is a platform-neutral, wire-level protocol for message-oriented middleware. The Spring AMQP project applies core Spring concepts to the development of AMQP-based messaging solutions. Spring Boot offers several conveniences for working with AMQP through RabbitMQ, including the spring-boot-starter-amqp “Starter”.
高级消息队列协议(AMQP)是面向消息中间件的平台中立的有线级协议。Spring AMQP项目将Spring的核心概念应用到基于AMQP的消息传递解决方案的开发中。Spring Boot为通过RabbitMQ与AMQP合作提供了一些便利,包括Spring Boot - Starter - AMQP“Starter”。

14.2.1. RabbitMQ support
RabbitMQ is a lightweight, reliable, scalable, and portable message broker based on the AMQP protocol. Spring uses RabbitMQ to communicate through the AMQP protocol.

RabbitMQ configuration is controlled by external configuration properties in spring.rabbitmq.*. For example, you might declare the following section in application.properties:

RabbitMQ是一种轻量级、可靠、可扩展、可移植的基于AMQP协议的消息代理。Spring使用RabbitMQ通过AMQP协议进行通信。RabbitMQ的配置是由spring.rabbitmq.*中的外部配置属性控制的。例如,你可以在application.properties中声明以下部分:

PropertiesYaml
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

Alternatively, you could configure the same connection using the addresses attribute:
或者,你可以配置相同的连接使用地址属性:

PropertiesYaml
spring.rabbitmq.addresses=amqp://admin:secret@localhost

When specifying addresses that way, the host and port properties are ignored. If the address uses the amqps protocol, SSL support is enabled automatically.
If a ConnectionNameStrategy bean exists in the context, it will be automatically used to name connections created by the auto-configured ConnectionFactory. See RabbitProperties for more of the supported options.

See Understanding AMQP, the protocol used by RabbitMQ for more details.

PropertiesYaml
spring.rabbitmq.addresses = amqp: / / admin: secret@localhost
当以这种方式指定地址时,主机和端口属性将被忽略。如果地址使用amqps协议,SSL支持将自动启用。
如果上下文中存在ConnectionNameStrategy bean,则将自动使用它来命名由自动配置的ConnectionFactory创建的连接。查看RabbitProperties获得更多支持的选项。
更多细节请参见理解RabbitMQ所使用的协议AMQP。

14.2.2. Sending a Message
Spring’s AmqpTemplate and AmqpAdmin are auto-configured, and you can autowire them directly into your own beans, as shown in the following example:

Spring的AmqpTemplate和AmqpAdmin是自动配置的,你可以将它们直接自动装配到你自己的bean中,如下面的例子所示:

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

@Component
public class MyBean {

    private final AmqpAdmin amqpAdmin;
    private final AmqpTemplate amqpTemplate;

    @Autowired
    public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.amqpTemplate = amqpTemplate;
    }

    // ...

}

RabbitMessagingTemplate can be injected in a similar manner. If a MessageConverter bean is defined, it is associated automatically to the auto-configured AmqpTemplate.
If necessary, any org.springframework.amqp.core.Queue that is defined as a bean is automatically used to declare a corresponding queue on the RabbitMQ instance.

To retry operations, you can enable retries on the AmqpTemplate (for example, in the event that the broker connection is lost):

PropertiesYaml
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s

Retries are disabled by default. You can also customize the RetryTemplate programmatically by declaring a RabbitRetryTemplateCustomizer bean.

If you need to create more RabbitTemplate instances or if you want to override the default, Spring Boot provides a RabbitTemplateConfigurer bean that you can use to initialize a RabbitTemplate with the same settings as the factories used by the auto-configuration.

RabbitMessagingTemplate可以以类似的方式注入。如果定义了MessageConverter bean,它将自动关联到自动配置的AmqpTemplate。如果有必要,任何org.springframework.amq .core都可以。定义为bean的Queue被自动用于在RabbitMQ实例上声明一个对应的Queue。要重试操作,您可以在AmqpTemplate上启用重试(例如,在代理连接丢失的情况下):

PropertiesYaml
spring.rabbitmq.template.retry.enabled = true
spring.rabbitmq.template.retry.initial-interval = 2s

默认情况下,重试是禁用的。你也可以通过声明一个RabbitRetryTemplateCustomizer bean来通过编程方式定制RetryTemplate。如果你需要创建更多的RabbitTemplate实例,或者你想覆盖默认值,Spring Boot提供了一个RabbitTemplateConfigurer bean,你可以用它来初始化一个RabbitTemplate,使用与自动配置工厂相同的设置。

14.2.3. Receiving a Message
When the Rabbit infrastructure is present, any bean can be annotated with @RabbitListener to create a listener endpoint. If no RabbitListenerContainerFactory has been defined, a default SimpleRabbitListenerContainerFactory is automatically configured and you can switch to a direct container using the spring.rabbitmq.listener.type property. If a MessageConverter or a MessageRecoverer bean is defined, it is automatically associated with the default factory.

The following sample component creates a listener endpoint on the someQueue queue:
当Rabbit基础架构存在时,任何bean都可以用@RabbitListener进行注释,以创建侦听器端点。
如果没有RabbitListenerContainerFactory被定义,默认的SimpleRabbitListenerContainerFactory被自动配置,你可以使用spring.rabbitmq.listener.type 属性切换到直接容器。如果定义了MessageConverter或MessageRecoverer bean,它将自动与默认工厂相关联。

下面的示例组件在someQueue队列上创建了一个侦听器端点:

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue")
    public void processMessage(String content) {
        // ...
    }

}

See the Javadoc of @EnableRabbit for more details.

查看@EnableRabbit 的Java文档获取更多的细节

If you need to create more RabbitListenerContainerFactory instances or if you want to override the default, Spring Boot provides a SimpleRabbitListenerContainerFactoryConfigurer and a DirectRabbitListenerContainerFactoryConfigurer that you can use to initialize a SimpleRabbitListenerContainerFactory and a DirectRabbitListenerContainerFactory with the same settings as the factories used by the auto-configuration.

如果你需要取创建更多的RabbitListenerContainerFactory 实例,或者你想重写默认的配置,你能用spring boot分别提供的一个SimpleRabbitListenerContainerFactoryConfigurer 和DirectRabbitListenerContainerFactoryConfigurer接口去用类似的设置去初始化一个SimpleRabbitListenerContainerFactory和一个DirectRabbitListenerContainerFactory,以此通过spring boot的auto-configuration(spring boot自动配置)来作为factories被使用;

It does not matter which container type you chose. Those two beans are exposed by the auto-configuration.

选择哪种容器类型无关紧要。这两个bean由自动配置公开。

For instance, the following configuration class exposes another factory that uses a specific MessageConverter:

例如,下面的配置类公开了另一个使用特定MessageConverter(消息转换器)的工厂:

@Configuration(proxyBeanMethods = false)
static class RabbitConfiguration {
	@Bean
	public SimpleRabbitListenerContainerFactory myFactory(
        SimpleRabbitListenerContainerFactoryConfigurer configurer) {
    		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    		configurer.configure(factory, connectionFactory);
    		factory.setMessageConverter(myMessageConverter());
    		return factory;
    }
}

Then you can use the factory in any @RabbitListener-annotated method, as follows:

然后你能在任何被@rabbitListener注解的方法上用这个工厂,如下所示:


@Component
public class MyBean {

    @RabbitListener(queues = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

You can enable retries to handle situations where your listener throws an exception. By default, RejectAndDontRequeueRecoverer is used, but you can define a MessageRecoverer of your own. When retries are exhausted, the message is rejected and either dropped or routed to a dead-letter exchange if the broker is configured to do so. By default, retries are disabled. You can also customize the RetryTemplate programmatically by declaring a RabbitRetryTemplateCustomizer bean.

您可以启用重试,以处理侦听器抛出异常的情况。默认情况下使用的是RejectAndDontRequeueRecoverer,但您可以定义自己的MessageRecoverer。当重试结束时,消息将被拒绝,如果代理配置为这样做,则消息将被丢弃或路由到死信交换。
默认情况下,重试是禁用的。你也可以通过声明一个RabbitRetryTemplateCustomizer bean来通过编程方式定制RetryTemplate。

By default, if retries are disabled and the listener throws an exception, the delivery is retried indefinitely. You can modify this behavior in two ways: Set the defaultRequeueRejected property to false so that zero re-deliveries are attempted or throw an AmqpRejectAndDontRequeueException to signal the message should be rejected. The latter is the mechanism used when retries are enabled and the maximum number of delivery attempts is reached.

默认情况下,如果重试被禁用并且侦听器抛出异常,则传递将无限期重试。您可以通过两种方式修改此行为:将defaultrequeuerejecjec属性设置为false,以便尝试零重新传递,或者抛出AmqpRejectAndDontRequeueException来表示应该拒绝该消息。后者是启用重试和达到交付尝试的最大数量时使用的机制。

2、环境搭建

1. 安装rabbitMQ

注:本人用的是docker,所以一下rabbitMQ安装用的都是docker环境。

第一步:搜索镜像

docker hub上搜索rabbitMQ镜像,如果直接在机器中用docker搜索镜像,用如下命令:

docker search rabbitmq

第二步:安装镜像

在docker中选择要安装的镜像版本,然后输入如下命令:

docker pull rabbitmq:3.8.9-management

注:代management的都有web管理界面

第三步:查看刚才安装的镜像ID

输入如下命令查看

docker images

本人的如下图所示

在这里插入图片描述

第四步:启动镜像

docker run -d --name myRabbitMQ -p 5672:5672 -p 15672:15672 imageID

  • -d:表示后台运行镜像
  • –name:给运行的镜像起一个名字
  • -p:将应用的端口号向外映射;5672:与rabbitMQ尽心消息交互的端口;15672:rabbitMQ自带的web管理界面

第五步:查看启动的镜像

输入如下命令查看

docker ps

第六步:查看rabbitMQ的管理界面

随便打开一个浏览器,在地址栏处输入你的host:the management client of rabbitMQ port来访问,如下图示:

在这里插入图片描述

**账号和密码默认都是:guest;**上面的红框部分,地址是我虚拟机端口号,读者填成自己的。

进入管理界面如下图所示:

在这里插入图片描述

名词和功能解释:

  • overview :概览,查看当前rabbitMQ的服务运行状态。
  • connection:链接,查看链接信息以及数量
  • channel:信道,查看信道状况,前面说过,rabbitMQ是一个tcp持续链接,采用信道传输信息的消息中间件
  • exchange:消息交换机,查看消息交换机状态以及信息
  • queues:消息队列,查看消息队列,再提一嘴,exchange和queues是多对多关系
  • admin:账户,查看账户信息
  • virtual host:虚拟主机,选择当前主机,上面的all表示所有的Host都显示,这是采用地址来区分的,如果virtual host="/vh1",表示查看vh1下的信息
  • refresh:刷新,后面的选择表示多少秒刷新一次
2. 使用rabbitMQ管理界面测试
  1. 因为exchange有四种类型,这里四种都进行测试。创建四个交换器,如下所示:

在这里插入图片描述

上面红色的部分是系统自有的交换机,蓝色的为我创建的(只创建了三个,headers不常用,懒得创)。创建一个交换机,除了必要的名字外,其它的属性解释如下:

  • type:交换机类型,四种:direct,topic,headers,fanout
  • durability:持久化策略,两种
    • durable:持久的,表示在交换机exchange宕机或者说意外停止服务的时候,此交换机保存的消息仍然存在。换句话说就是下次启动rabbitMQ的时候,这个消息还在消息队列。
    • transient:短暂的,表示交换机exchange宕机或者说意外停止服务的时候,此交换机保存的消息将被清除。换句话说就是下次启动rabbitMQ的时候,这个消息不存在了。
  • auto delete:自动删除,yes表示采用rabbitMQ自动删除策略;No表示不采用
  • internal:是否是内部交换机,交换机可以互联,有的交换机可以不对外开放,说的就是这种不开放的交换机
  • arguments:交换机参数,这个是用在headers类型交换机上的,交换机接到message后,解析head信息进行比对,如果比对成功,则将消息传递到此exchange。
  1. 创建四个消息队列,分别为lm66.news、lm.news、lm.emps、lm,如下图所示:

在这里插入图片描述

如上图,在创建一个新的队列时有如下属性选择:

  • type:队列类型,两种:

    • classic:传统的

    • quorum:仲裁队列(rabbitMQ3.8.0 up 开始支持)

      两者区别如下所示:

      FeatureClassic MirroredQuorum
      Non-durable queues(非持久队列)yesno
      Exclusivity(排他性)yesno
      Per message persistence(每条消息持久化策略)per messagealways
      Membership changes(身份变更,直译为会员交流或者会员改变)automaticmanual
      TTLyesno
      Queue length limits(队长限制)yespartial (drop-head strategy only)
      Lazy behaviour(懒加载)yespartial (see Memory Limit)
      Message priority(消息优先级)yesno
      Consumer priority(消费优先级)yesno
      Dead letter exchanges(死信交换)yesyes
      Adheres to policies(坚持政策)yespartial (dlx, queue length limits)
      Reacts to memory alarms(内存警告响应)yespartial (truncates log)
      Poison message handling(有害信息(毒信息)处理)noyes
      Global QoS Prefetch(全局Qos预载)yesno

    其他属性和上面的exchange相差不多,在这不做过多介绍。

  1. 将消息队列分别绑定到交换机上

lm.direct 和 lm.fanout做全部绑定,lm.topic做通配符绑定。先绑定lm.direct,如下图所示:(直接到exchange标签页,点击表格里面的交换机名就可以转到如下绑定界面)

在这里插入图片描述

上面有个to queue表示此交换机连到队列,to exchange表示此交换机连到交换机。链接到队列,就填队列名称;连接到交换机,就填交换机名称。

routing key:路由键,交换机之间通信的规则,随便写。不过我建议和链接到的队列名或者交换机同名,如果使用通配符,建议包含队列的识别信息。

argument:设置传递参数。

注:lm.fanout也做如上绑定设置。

下面是lm.topic交换机的绑定,如下图示:

在这里插入图片描述

通配符释意:

  • #号表示匹配一个或者多个单词
  • *号表示匹配一个单词
  1. 利用交换机发送消息

第一步:进入交换机信息查看界面

在这里插入图片描述

第二步:点击publish message到如下界面发送消息

在这里插入图片描述

看见routing key了吧?这就是路由交换规则,在这个里面可以填任何值,如果没有此路由键则发不出去呗,如果有则发送到相应的消息队列种。如果我填lm,则发送到lm对应的lm队列种,如果我填lm.#,则发送到lm.emps和lm.news队列中,到这,多的不用说了吧?

注意:direct是point to point式的发送,通配符没用,必须直接给出队列的路由键。例如,lm.*是没用的,不能匹配到lm.emps和lm.news。fanout是扩展式发送,类似于广播,就是路由键不管是什么,都将发送给此交换机下所有的队列。

只有topic式的交换机支持通配符,但是topic在发送消息使用通配符时,只能进行完全匹配。例如,有两个消息队列,分别是lm.emps和lm.news,其绑定到topic上的路由键分别为lm.#和*.news,如果我在发送消息时指定匹配规则为lm.#,按理说两个消息队列都应该收到消息,因为*号匹配lm,#号匹配news,但事实是只发送给的路由键是lm.#的消息队列lm.emps。由此得如果是发送消息时,路由键包含通配符,则通配符失效。

那么如何给两个队列发消息呢?

可以指定发送消息时routing-key=lm.news,lm.news将完全适配lm.#和*.news路由键。

  1. 查看发送的消息

进入队列查看界面,直接点击队列名称进入队列信息界面,下拉有个get messaage选项,点进去点get就OK了,如下图:

在这里插入图片描述

上面有个ack mode选项,其中requeue true表示获取消息后,消息仍然被队列保存;如果时requeue false,则表示获取消息后,消息从队列删除。

2. spring boot环境准备

第一步:创建一个空的spring boot项目

第二步:引入如下启动器依赖

<!-- amqp协议支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- rabbit测试-->
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- spring boot测试-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

第三步:编写配置文件

spring:
  rabbitmq:
    host: 192.168.43.37 # 默认local host,我用的是虚拟机加docker,所以是虚拟机的ip地址
    username: guest # 默认也是guest
    password: guest # 默认也是guest
    virtual-host: / # 默认也是“/”

第四步:编写测试类

package com.lm.rabbitMQ;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.Map;

@SpringBootTest
class LmApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RabbitAdmin rabbitAdmin;

    @Autowired
    AmqpAdmin amqpAdmin;

    /**
     * rabbitTemplate 是spring boot提供的消息操作类,主要用来发送消息和接收消息;
     * rabbitTemplate 提供了两种发送方法:
     *      1. send()方法,里面需要传递一个message消息对象,这个对象需要自己定义;
     *      2. convertAndSend()方法,这个直接可以传递一个object对象,这个对象会直接被转换为字节数组并发送;
     *      注意: 发送的对象最后都会被序列化成字节码,可以自己指定序列化,请看我配的json序列化配置类;
     * rabbitTemplate 提供了两种接收方法:
     *      1. receive()方法,接收消息队列的信息,但是接收来的是序列化后的信息
     *      2. receiveAndConvert()方法,接收消息队列的信息并转换为正常对象
     */
    @Test
    void testSend(){
        // exchange参数指定由谁去发送消息
        // routine-key指定发送的路由键
        // object指定发送的数据对象
        rabbitTemplate.convertAndSend("lm.news","lm","hello word!!!");
        // rabbitTemplate.send(Message message)方法,也可以发送消息,但是message需要自己给定,读者可以点看这个方法看构造类和其属性

//        以json格式序列化发送
//        Map<String,String> map = new HashMap<>();
//        map.put("1","a");
//        map.put("2","b");
//        map.put("3","c");
//        map.put("4","d");
//        rabbitTemplate.convertAndSend("lm.news","lm",map);
        System.out.println("successfully send!!!");
    }

    @Test
    void testReceive(){
        // rabbitTemplate.receiveAndConvert(String queueName) queueName参数直接指定队列名称,其他的重载方法不常用,这个接收后直接转换消息为对象object
        Object lm = rabbitTemplate.receiveAndConvert("lm");
        System.out.println(lm.getClass());
        System.out.println(lm);
    }

    /**
     * AmqpTemplate和RabbitTemplate类是用来操作消息的
     * AmqpAdmin和rabbitAdmin类是用来操作exchange和queue对象的,包括CRUD,即增删改查
     */
    @Test
    void testBroker(){
        Exchange exchange = new DirectExchange("lm666"); // 创建一个direct类型的exchange,名为lm666
        Exchange exchange1 = new FanoutExchange("lm666"); // 创建一个fanout类型的exchange,名为lm666
        Exchange exchange2 = new TopicExchange("lm666"); // 创建一个topic类型的exchange,名为lm666
        Exchange exchange3 = new HeadersExchange("lm666"); // 创建一个headers类型的exchange,名为lm666
//        amqpAdmin.declareExchange(Exchange exchange);declare声明一个exchange对象到rabbitMQ种
//        amqpAdmin.declareQueue(Queue queue);声明一个queue
//        amqpAdmin.declareBinding(Binding binding);声明一个路由绑定规则
        // 读者自测吧
    }
}


注:到第四步,就可以着手开始操作测试了

第五步:搭建如下项目目录结构

在这里插入图片描述

第六步:编写json序列化配置类MyAmqbConfig.java类

package com.lm.rabbitMQ.config;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置rabbitMQ消息序列化类型,配置为json
 */
@Configuration
public class MyAmqbConfig {

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
}

第七步:编写order.java订单类和orderService.java服务类

Order.java

package com.lm.rabbitMQ.domain;

import java.util.Date;

public class Order {
    private Integer id;
    private String name;
    private Date date;

    public Order() {
    }

    public Order(Integer id, String name, Date date) {
        this.id = id;
        this.name = name;
        this.date = date;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", date=" + date +
                '}';
    }
}

OrderService.java(整合信息全在注解里面,多多阅读)

package com.lm.rabbitMQ.service;


import com.lm.rabbitMQ.domain.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;


/**
 * @RabbitListener 可以标注载类上,也可以标注载方法上,表示监听消息队列,具体的匹配规则,可以直接查看rabbitListener属性;
 * @RabbitHandler 此注解需要和RabbitListener配合使用,且只能注解在方法上,怎么使用呢?RabbitListener表示接收消息队列的消息,接收到的消息然
 *      后通过messageConvert实现类来转换消息为对象,然后根据对象和方法种的参数进行匹配,匹配成功后然后执行对应的方法,如果多个匹配,那个多个方法执行。
 * @Payload 标注在方法中的形参中,表示接收消息的body;
 * @Headers 标注在方法中的形参中,表示接收消息的headers;
 * 例如如下所示:
 *      public void method(@Payload String body, @Headers Map<String,Object> headers)
 * 一个关于rabbitListener注解的复杂属性配置:
 * @RabbitListener(bindings = @QueueBinding(
 *         exchange = @Exchange(value = "lm.topic",durable = "true",type = "topic"),
 *         value = @Queue(value = "queue_name",durable = "true"),
 *         key = "routing-key"
 * ))
 * 上面这个复杂配置中,bindings表示绑定规则,在上面中有@QueueBinding表示队列绑定规则;如果绑定规则不存在,则里面的@Exchange、@Queue、key自动
 *      加载;如果存在,则抛出异常。
 *      @Exchange 表示创建一个exchange交换机
 *      @Queue 表示创建一个queue队列
 *      key 表示指定绑定路由键规则
 */
@Slf4j
@Service
public class OrderService {


    @RabbitListener(queues = "lm66")
    public void receiveAndHandlingOrder(Order order){
        log.info(order.toString());
    }

    @RabbitListener(queues = "lm66")
    public void receiveOrder(Message message){
        // message对象里面包含队列传递过来的消息,可以把消息根据自己的需求进行处理
        log.info(String.valueOf(message.getBody()));
    }
}

第八步:编写测试类OrderServiceTest.java

package com.lm.rabbitMQ.service;

import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.UnsupportedEncodingException;

@SpringBootTest
class OrderServiceTest {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void receiveAndHandlingOrder() {
        rabbitTemplate.convertAndSend("lm.direct", "lm", "hello world");
    }

    @Test
    void receiveOrder() throws UnsupportedEncodingException {
        byte[] bytes = "hello world".getBytes("utf-8");
        Message message = new Message(bytes, new MessageProperties());
        rabbitTemplate.send("lm.direct", "lm", message);
    }
}

读者自测,本人已经测试通过


项目地址:https://gitee.com/liu_liangyuan/spring-boot_learning/tree/master/springboot_rabbitMQ

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值