RabbitMQ

1.简单队列

最基础的消息队列模型,只包括三个角色:

publisher:消息发布者,将消息发送到队列queue

queue:消息队列,负责接受并缓存消息

consumer:订阅队列,处理队列中的消息

我们创建一个mevan的问文件,其中在consumer上实现消费者,在publisher上实现发布者。pom.xml导入依赖。

1.1 Publisher实现

思路:

  • 建立连接
  • 创建Channel
  • 声明队列
  • 发送消息
  • 关闭连接和channel
java 复制代码
package cn.itcast.mq.helloworld;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.junit.Test;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class PublisherTest {
    @Test
    public void testSendMessage() throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.发送消息
        String message = "hello, rabbitmq!";
        channel.basicPublish("", queueName, null, message.getBytes());
        System.out.println("发送消息成功:【" + message + "】");

        // 5.关闭通道和连接
        channel.close();
        connection.close();

    }
}

1.2consumer实现

代码思路:

  • 建立连接
  • 创建Channel
  • 声明队列
  • 订阅消息
  • 代码实现:
java 复制代码
package cn.itcast.mq.helloworld;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

public class ConsumerTest {

    public static void main(String[] args) throws IOException, TimeoutException {
        // 1.建立连接
        ConnectionFactory factory = new ConnectionFactory();
        // 1.1.设置连接参数,分别是:主机名、端口号、vhost、用户名、密码
        factory.setHost("192.168.150.101");
        factory.setPort(5672);
        factory.setVirtualHost("/");
        factory.setUsername("itcast");
        factory.setPassword("123321");
        // 1.2.建立连接
        Connection connection = factory.newConnection();

        // 2.创建通道Channel
        Channel channel = connection.createChannel();

        // 3.创建队列
        String queueName = "simple.queue";
        channel.queueDeclare(queueName, false, false, false, null);

        // 4.订阅消息
        channel.basicConsume(queueName, true, new DefaultConsumer(channel){
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope,
                                       AMQP.BasicProperties properties, byte[] body) throws IOException {
                // 5.处理消息
                String message = new String(body);
                System.out.println("接收到消息:【" + message + "】");
            }
        });
        System.out.println("等待接收消息。。。。");
    }
}

2.SpringAMQP

SpringAMQP是基于RabbitMQ封装的一套模板,并且还利用SpringBoot对其实现了自动装配,使用起来非常方便。

SpringAmqp的官方地址:https://spring.io/projects/spring-amqp

SpringAMQP提供了三个功能:

  • 自动声明队列、交换机及其绑定关系
  • 基于注解的监听器模式,异步接收消息
  • 封装了RabbitTemplate工具,用于发送消息

3.Basic Queue 简单队列模型

3.1依赖引入

在父工程mq-demo中引入依赖

xml 复制代码
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

3.2消息发送

首先配置MQ地址,在publisher服务的application.yml中添加配置:

yml 复制代码
spring:
  rabbitmq:
    host: 192.168.150.101 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: itcast # 用户名
    password: 123321 # 密码

然后在publisher服务中编写测试类SpringAmqpTest,并利用RabbitTemplate实现消息发送:

java 复制代码
package cn.itcast.mq.spring;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
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 SpringAmqpTest {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testSimpleQueue() {
        // 队列名称
        String queueName = "simple.queue";
        // 消息
        String message = "hello, spring amqp!";
        // 发送消息
        rabbitTemplate.convertAndSend(queueName, message);
    }
}

3.3 消息接收

首先配置MQ地址,在consumer服务的application.yml中添加配置:

yml 复制代码
spring:
  rabbitmq:
    host: 192.168.150.101 # 主机名
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: itcast # 用户名
    password: 123321 # 密码

然后在consumer服务的cn.itcast.mq.listener包中新建一个类SpringRabbitListener,代码如下:

java 复制代码
package cn.itcast.mq.listener;

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

@Component
public class SpringRabbitListener {

    @RabbitListener(queues = "simple.queue")
    public void listenSimpleQueueMessage(String msg) throws InterruptedException {
        System.out.println("spring 消费者接收到消息:【" + msg + "】");
    }
}

4.WorkQueue

Work queues,也被称为(Task queues),任务模型。简单来说就是让多个消费者绑定到一个队列,共同消费队列中的消息。

当消息处理比较耗时的时候,可能生产消息的速度会远远大于消息的消费速度。长此以往,消息就会堆积越来越多,无法及时处理。

此时就可以使用work 模型,多个消费者共同处理消息处理,速度就能大大提高了。

4.1.消息发送

这次我们循环发送,模拟大量消息堆积现象。

在publisher服务中的SpringAmqpTest类中添加一个测试方法:

这个队列发送消息和前面的基本一样,就是通过rabbitTemplate一直在发送消息(发送50条),不过我们通过Thread.sleep(20)进行线程休眠,这样就能保证每20ms发送一条,1s发送50条消息。

java 复制代码
/**
     * workQueue
     * 向队列中不停发送消息,模拟消息堆积。
     */
@Test
public void testWorkQueue() throws InterruptedException {
    // 队列名称
    String queueName = "simple.queue";
    // 消息
    String message = "hello, message_";
    for (int i = 0; i < 50; i++) {
        // 发送消息
        rabbitTemplate.convertAndSend(queueName, message + i);
        Thread.sleep(20);
    }
}

4.2.消息接收

要模拟多个消费者绑定同一个队列,我们在consumer服务的SpringRabbitListener中添加2个新的方法:

消费者1是20ms处理一条消息,消费者2是100ms处理一条消息。

java 复制代码
    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue1(String msg) throws InterruptedException
    {
        System.out.println("消费者1接收到信息:【"+msg+"】"+ LocalTime.now());
        Thread.sleep(20);
    }

    @RabbitListener(queues = "simple.queue")
    public void listenWorkQueue2(String msg) throws InterruptedException {
        System.out.println("消费者2接收到信息:【"+msg+"】"+ LocalTime.now());
        Thread.sleep(100);
    }

启动ConsumerApplication后,在执行publisher服务中刚刚编写的发送测试方法testWorkQueue。可以看到消费者1很快完成了自己的25条消息。消费者2却在缓慢的处理自己的25条消息。也就是说消息是平均分配给每个消费者,并没有考虑到消费者的处理能力。这样显然是有问题的。

测试结果:

消费者1接收到信息:【hello message_0】13:03:41.553492300

消费者2接收到信息:【hello message_1】13:03:41.571944300

消费者1接收到信息:【hello message_2】13:03:41.603588

消费者1接收到信息:【hello message_4】13:03:41.665707600

消费者2接收到信息:【hello message_3】13:03:41.679711500

消费者1接收到信息:【hello message_6】13:03:41.727969800

消费者2接收到信息:【hello message_5】13:03:41.787886800

消费者1接收到信息:【hello message_8】13:03:41.789926600

消费者1接收到信息:【hello message_10】13:03:41.851753300

消费者2接收到信息:【hello message_7】13:03:41.897548600

消费者1接收到信息:【hello message_12】13:03:41.914960800

消费者1接收到信息:【hello message_14】13:03:41.976471

消费者2接收到信息:【hello message_9】13:03:42.005577700

消费者1接收到信息:【hello message_16】13:03:42.038146300

消费者1接收到信息:【hello message_18】13:03:42.100719800

消费者2接收到信息:【hello message_11】13:03:42.114777400

消费者1接收到信息:【hello message_20】13:03:42.162530300

消费者2接收到信息:【hello message_13】13:03:42.222722500

消费者1接收到信息:【hello message_22】13:03:42.224714100

消费者1接收到信息:【hello message_24】13:03:42.286619400

消费者2接收到信息:【hello message_15】13:03:42.331403700

消费者1接收到信息:【hello message_26】13:03:42.348780400

消费者1接收到信息:【hello message_28】13:03:42.410712600

消费者2接收到信息:【hello message_17】13:03:42.442490700

消费者1接收到信息:【hello message_30】13:03:42.475415800

消费者1接收到信息:【hello message_32】13:03:42.536355800

消费者2接收到信息:【hello message_19】13:03:42.549882

消费者1接收到信息:【hello message_34】13:03:42.598142300

消费者2接收到信息:【hello message_21】13:03:42.660076800

消费者1接收到信息:【hello message_36】13:03:42.661782900

消费者1接收到信息:【hello message_38】13:03:42.724909100

消费者2接收到信息:【hello message_23】13:03:42.769704200

消费者1接收到信息:【hello message_40】13:03:42.786581100

消费者1接收到信息:【hello message_42】13:03:42.848215

消费者2接收到信息:【hello message_25】13:03:42.879209200

消费者1接收到信息:【hello message_44】13:03:42.912857900

消费者1接收到信息:【hello message_46】13:03:42.973724300

消费者2接收到信息:【hello message_27】13:03:42.987657500

消费者1接收到信息:【hello message_48】13:03:43.037572700

消费者2接收到信息:【hello message_29】13:03:43.097594

消费者2接收到信息:【hello message_31】13:03:43.206823100

消费者2接收到信息:【hello message_33】13:03:43.317514300

消费者2接收到信息:【hello message_35】13:03:43.426855900

消费者2接收到信息:【hello message_37】13:03:43.535199100

消费者2接收到信息:【hello message_39】13:03:43.645428200

消费者2接收到信息:【hello message_41】13:03:43.755271300

消费者2接收到信息:【hello message_43】13:03:43.862493600

消费者2接收到信息:【hello message_45】13:03:43.970638700

消费者2接收到信息:【hello message_47】13:03:44.079064500

消费者2接收到信息:【hello message_49】13:03:44.186677100

4.3 消息预存机制

rabbitMQ内部有消息预取机制,比如有两个消费队列,共同去消费50条消息,即便这两台机器有差异,也会因为消息预取机制,每台机器去抢25条消息,从而影响整体效率。

要解决可以在配置中限制消息预取的数量,原来默认是没有上限,现在可以限制为1,即每次处理完当前的消息之后再去队列中获取新的消息。

bash 复制代码
spring:
    listener:
      simple:
        prefetch: 1 # 每次只能获取i条消息,处理完才能获取下一条信息

测试结果:1s完成处理

消费者1接收到信息:【hello message_0】13:10:49.127502600

消费者2接收到信息:【hello message_1】13:10:49.150574200

消费者1接收到信息:【hello message_2】13:10:49.181642300

消费者1接收到信息:【hello message_3】13:10:49.213763200

消费者1接收到信息:【hello message_4】13:10:49.243518400

消费者1接收到信息:【hello message_5】13:10:49.275451300

消费者2接收到信息:【hello message_6】13:10:49.305015400

消费者1接收到信息:【hello message_7】13:10:49.336716200

消费者1接收到信息:【hello message_8】13:10:49.367798800

消费者1接收到信息:【hello message_9】13:10:49.397585

消费者2接收到信息:【hello message_10】13:10:49.429614100

消费者1接收到信息:【hello message_11】13:10:49.460835500

消费者1接收到信息:【hello message_12】13:10:49.490800100

消费者1接收到信息:【hello message_13】13:10:49.523759900

消费者1接收到信息:【hello message_14】13:10:49.553686300

消费者2接收到信息:【hello message_15】13:10:49.584685200

消费者1接收到信息:【hello message_16】13:10:49.613932300

消费者1接收到信息:【hello message_17】13:10:49.645967400

消费者1接收到信息:【hello message_18】13:10:49.676633100

消费者1接收到信息:【hello message_19】13:10:49.708264800

消费者2接收到信息:【hello message_20】13:10:49.738056300

消费者1接收到信息:【hello message_21】13:10:49.769481700

消费者1接收到信息:【hello message_22】13:10:49.799894600

消费者1接收到信息:【hello message_23】13:10:49.830995400

消费者1接收到信息:【hello message_24】13:10:49.863635700

消费者2接收到信息:【hello message_25】13:10:49.901455900

消费者1接收到信息:【hello message_26】13:10:49.926726600

消费者1接收到信息:【hello message_27】13:10:49.957282800

消费者1接收到信息:【hello message_28】13:10:49.987841800

消费者1接收到信息:【hello message_29】13:10:50.020863

消费者2接收到信息:【hello message_30】13:10:50.052703600

消费者1接收到信息:【hello message_31】13:10:50.084854800

消费者1接收到信息:【hello message_32】13:10:50.115834500

消费者1接收到信息:【hello message_33】13:10:50.147856200

消费者1接收到信息:【hello message_34】13:10:50.177959700

消费者2接收到信息:【hello message_35】13:10:50.208759800

消费者1接收到信息:【hello message_36】13:10:50.239049100

消费者1接收到信息:【hello message_37】13:10:50.270743900

消费者1接收到信息:【hello message_38】13:10:50.301039100

消费者1接收到信息:【hello message_39】13:10:50.333678800

消费者2接收到信息:【hello message_40】13:10:50.363239200

消费者1接收到信息:【hello message_41】13:10:50.395528600

消费者1接收到信息:【hello message_42】13:10:50.425473500

消费者1接收到信息:【hello message_43】13:10:50.457002500

消费者1接收到信息:【hello message_44】13:10:50.487832

消费者2接收到信息:【hello message_45】13:10:50.519196400

消费者1接收到信息:【hello message_46】13:10:50.552032600

消费者1接收到信息:【hello message_47】13:10:50.581058600

消费者1接收到信息:【hello message_48】13:10:50.611802700

消费者1接收到信息:【hello message_49】13:10:50.642628300

5.发布订阅模型

可以看到,在订阅模型中,多了一个exchange角色,而且过程略有变化:

  • Publisher:生产者,也就是要发送消息的程序,但是不再发送到队列中,而是发给X(交换机)
  • Exchange:交换机,图中的X。一方面,接收生产者发送的消息。另一方面,知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有以下3种类型:
    -- Fanout:广播,将消息交给所有绑定到交换机的队列
    -- Direct:定向,把消息交给符合指定routing key 的队列
    --Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列
  • Consumer:消费者,与以前一样,订阅队列,没有变化
  • Queue:消息队列也与以前一样,接收消息、缓存消息。
  • Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

6. Fanout 广播模型

在广播模式下,消息发送流程是这样的

  • 1)可以有多个队列
    1. 每个队列都要保定到Exchange(交换机)
  • 3)生产者发送的消息只有到了交换机,交换机来决定消息该发给那些队列,生产者无法决定
  • 4)交换机包消息发送给绑定过的所有队列
  • 5) 订阅队列的消费者都能拿到消息

我们创建一台名为itcast.fanout的exchange,创建两个队列分别绑定到交换机上。

在consumer中创建一个类,声明队列和交换机。

java 复制代码
package cn.itcast.mq;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class config {
    //声明交换机exchange,返回值为fanout
    @Bean
    public FanoutExchange fanoutExchange()
    {
        return new FanoutExchange("itcast.fanout");
    }

    // 第一个队列
    @Bean
    public Queue fanoutQueue1()
    {
        return new Queue("fanout.queue1");
    }
    // 绑定队列和交换机
    @Bean
    public Binding bindingQueue1(Queue fanoutQueue1,FanoutExchange fanoutExchange)
    {
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    // 第二个队列
    @Bean
    public Queue fanoutQueue2()
    {
        return new Queue("fanout.queue2");
    }
    // 绑定队列和交换机
    @Bean
    public Binding bindingQueue2(Queue fanoutQueue2,FanoutExchange fanoutExchange)
    {
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }
}

在publisher服务的SpringAMqpTest类中添加测试方法:

java 复制代码
    @Test
    public void testFanoutExchange()
    {
        // 队列名称
        String exchangeName = "itcast.fanout";
        // 消息
        String message = "hello,everyone";
        rabbitTemplate.convertAndSend(exchangeName,"",message);
    }

在consumer服务的SpringRabbitLinstener中添加两个方法作为消费者。

java 复制代码
    @RabbitListener(queues = "fanout.queue1")
    public void listenFanoutQueue1(String msg)
    {
        System.out.println("消费者1接收到Fanout消息:"+msg);
    }

    @RabbitListener(queues = "fanout.queue2")
    public void listenFanoutQueue2(String msg)
    {
        System.out.println("消费者2接收到Fanout消息:"+msg);
    }

消息返回

消费者2接收到Fanout消息:hello,everyone

消费者1接收到Fanout消息:hello,everyone

交换机exchange的作用

1.接收publisher发送的消息

  1. 将消息按照规则路由到与之绑定的队列

  2. 不能缓存消息,路由失败,消息丢失

  3. fanoutExchange会将消息发送到每个绑定的队列上

7. Direct

在Fanout模式中,一条消息,会被所有订阅的队列都消费。但是,在某些场景下,我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。

在Direct模型下:

队列与交换机的绑定,不能是任意绑定了,而是要指定一个RoutingKey(路由key)

消息的发送方在 向 Exchange发送消息时,也必须指定消息的 RoutingKey。

Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routingkey与消息的 Routing key完全一致,才会接收到消息.

案例需求如下:

利用@RabbitListener声明Exchange、Queue、RoutingKey

在consumer服务中,编写两个消费者方法,分别监听direct.queue1和direct.queue2

在publisher中编写测试方法,向itcast. direct发送消息

7.1基于注解声明队列和交换机

基于@Bean的方式声明队列和交换机比较麻烦,Spring还提供了基于注解方式来声明。

在consumer的SpringRabbitListener中添加两个消费者,同时基于注解来声明队列和交换机:

java 复制代码
@RabbitListener(bindings = @QueueBinding(
            value = @Queue(name="dircet.queue1"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","blue"}
    ))
    public void listenDirectQueue1(String msg)
    {
        System.out.println("消费者接收到direct.queue1的消息:"+msg);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "dircet.queue2"),
            exchange = @Exchange(name = "itcast.direct",type = ExchangeTypes.DIRECT),
            key = {"red","yellow"}
    ))
    public void listenDirectQueue2(String msg)
    {
        System.out.println("消费者接收到dircet.queue2的消息:"+msg);
    }

7.2 消息发送

在publisher服务的SpringAmqpTest类中添加测试方法:

java 复制代码
    @Test
    public void testSendDirectExchange()
    {
        // 交换机名称
        String exchangeName = "itcast.direct";
        // 消息
        String message = "红色警报,redred";
        rabbitTemplate.convertAndSend(exchangeName,"red",message);
    }

8 Topic

Topic类型的Exchange与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符!

Routingkey 一般都是有一个或多个单词组成,多个单词之间以"."分割,例如: item.insert

通配符规则:

#:匹配一个或多个词

*:匹配不多不少恰好1个词
举例:

item.#:能够匹配item.spu.insert 或者 item.spu

item.*:只能匹配item.spu

解释:

Queue1:绑定的是china.# ,因此凡是以 china.开头的routing key 都会被匹配到。包括china.news和china.weather

Queue2:绑定的是#.news ,因此凡是以 .news结尾的 routing key 都会被匹配。包括china.news和japan.news

实现思路如下:

  • 并利用@RabbitListener声明Exchange、Queue、RoutingKey
  • 在consumer服务中,编写两个消费者方法,分别监听topic.queue1和topic.queue2
  • 在publisher中编写测试方法,向itcast. topic发送消息

    在consumer服务的SpringRabbitListener中添加方法:
java 复制代码
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name="topic.queue1"),
            exchange = @Exchange(name="itcast.topic",type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void listenTopicQueue1(String msg)
    {
        System.out.println("消费者接收到topic.queue1的消息:"+msg);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name="topic.queue2"),
            exchange = @Exchange(name="itcast.topic",type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void listenTopicQueue2(String msg)
    {
        System.out.println("消费者接收到topic.queue2的消息:"+msg);
    }

在publisher服务的SpringAmqpTest类中添加测试方法:

java 复制代码
    @Test
    public void testsendTopicExchange()
    {
        //交换机名称
        String exchangeName = "itcast.topic";
        // 消息
        String message = "一条中国新闻....";
        // 发送消息
        rabbitTemplate.convertAndSend(exchangeName,"china.news",message);
    }

消费者接收到topic.queue2的消息:一条中国新闻...

消费者接收到topic.queue1的消息:一条中国新闻...

描述下Direct交换机与Topic交换机的差异?

Topic交换机接收的消息RoutingKey必须是多个单词,以 . 分割

Topic交换机与队列绑定时的bindingKey可以指定通配符

#:代表0个或多个词

*:代表1个词

9 消息转换器

Spring会把你发送的消息序列化为字节发送给MQ,接收消息的时候,还会把字节反序列化为Java对象。

只不过,默认情况下Spring采用的序列化方式是JDK序列化。众所周知,JDK序列化存在下列问题:

数据体积过大

有安全漏洞

可读性差

我们来测试一下。

9.1 默认的消息转换器

声明类中声明一个新的Queue

bash 复制代码
    @Bean
    public Queue objectQueue()
    {
        return new Queue("object.queue");
    }

我们修改消息发送的代码,发送一个Map对象:

java 复制代码
  @Test
    public void testSendMap() throws InterruptedException
    {
        // 准备消息
        Map<String, Object> msg = new HashMap<>();
        msg.put("name","Tom");
        msg.put("age",21);
        // 发送消息
        rabbitTemplate.convertAndSend("object.queue","",msg
        );
    }

停止consumer服务

发送消息后查看控制台:

9.2.配置JSON转换器

显然,JDK序列化方式并不合适。我们希望消息体的体积更小、可读性更高,因此可以使用JSON方式来做序列化和反序列化。

在publisher和consumer两个服务中都引入依赖:

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>

配置消息转换器。

在启动类中添加一个Bean即可:

java 复制代码
package cn.itcast.mq;

import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class PublisherApplication {
    public static void main(String[] args) {
        SpringApplication.run(PublisherApplication.class);
    }


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

9.2 接收消息

java 复制代码
@RabbitListener(queues = "object.queue")
public void listenObjectQueue(Map<String, Object>msg)
{
    System.out.println(msg);
}
相关推荐
茶杯梦轩2 天前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯3 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840823 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840825 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者6 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者8 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧9 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖10 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农10 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者10 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端