SpringAMQP

13 篇文章 0 订阅
5 篇文章 1 订阅

简介

Advanced Message Queuing Protocol(简称AMQP),是应用于在应用程序或之间传递业务信息的开发标准。该协议与语言和平台无关,更符合微服务中的独立性要求

Spring AMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息。包含两部分,其中spring-rabbit是底层的默认实现

基础功能

RabbitMQ安装

在使用之前需要安装RabbitMQ,安装教程

官方安装包下载有点慢,这里提供了阿里云盘分享的安装包:rabbitmq-server-3.11.8.exe

otp_win64_25.2.2.exe

注意:当执行命令报rabbitmq erlang_home not set correctly.错误时,rabbitmq_server-3.11.8\sbin目录中找到rabbitmq-server.bat进行编辑,并找到如下代码

if not exist "!ERLANG_HOME!\bin\erl.exe" (
    echo.
    echo ******************************
    echo ERLANG_HOME not set correctly.
    echo ******************************
    echo.
    echo Please either set ERLANG_HOME to point to your Erlang installation or place the
    echo RabbitMQ server distribution in the Erlang lib folder.
    echo.
    exit /B 1
)

请检查"!ERLANG_HOME!\bin\erl.exe"与环境变量Path是否配置正确,安装好后浏览器访问localhost:15672即可

引入Maven依赖

<!--amqp-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

发送端代码实现

application.yml配置

spring:
  rabbitmq:
    host: localhost  # 主机名
    port: 5672       # 端口
    virtual-host: /  # 虚拟主机
    username: guest # 用户名
    password: guest # 密码

注意:这里用的是5672端口,同时我使用的是系统默认的账号密码对应网页端如下

在这里插入图片描述

Java代码如下

 @Autowired
private RabbitTemplate rabbitTemplate;

@Test
void contextLoads() {
    String queueName = "simple.queue";
    String message = "发送消息";
    rabbitTemplate.convertAndSend(queueName, message);
}

其中queueName如下

在这里插入图片描述

执行该代码即可发送消息

接收端代码

@Component
public class SpringRabbitListener {
	// queues里使用的是队列的名称
    @RabbitListener(queues = "simple.queue")
    public void listenerSimpleQueue(String message) {
        System.out.println("接收到的消息 : " + message);
    }
}

注意:SpringAMQP一旦消费了消息就会销毁

WorkQueue

Work Queue即工作队列,可以提高消息的处理速度,避免消息堆积。由于一个消息生产者,一个消息消费者,一个消息队列。由于消息生产者比消息消费者生产的速度大于消费的速度,就会导致消息队列堆积,当消息队列堆积满后就导致消息丢失。

绑定多个监听者

@RabbitListener(queues = "simple.queue")
public void listenerWorkQueue1(String message) throws InterruptedException {
    System.out.println("work1接收到的消息 : " + message);
    Thread.sleep(20);
}

@RabbitListener(queues = "simple.queue")
public void listenerWorkQueue2(String message) throws InterruptedException {
    System.err.println("work2接收到的消息 : " + message);
    Thread.sleep(200);
}

发送多条消息

@Autowired
private RabbitTemplate rabbitTemplate;

@Test
void sendMessage() {
    String queueName = "simple.queue";
    String message = "发送消息 -- ";
    for (int i = 0; i < 50; i++) {
        rabbitTemplate.convertAndSend(queueName, message + i);
    }
}

由于RabbitTemplate默认会采用轮询策略来分发给不同的消费者,所以会导致work1和work2都获取到了25条消息。但现在由于消费者的消费能力不一致,所以希望消费能力强的消费者多消费来避免消息发送出现的拥堵情况

在application.yml文件配置如下来达到要求

spring:
  rabbitmq:
    host: localhost  # 主机名
    port: 5672       # 端口
    virtual-host: /  # 虚拟主机
    username: guest # 用户名
    password: guest # 密码
    listener:
      simple:
        prefetch: 1 # 每次只能获取一条消息,处理完才能获取下一条消息

发布订阅模型

发布订阅模式是允许将同一消息发送给多个消费者。实现方式是加入了exchange(交换机)

publisher
exchange
queue1
queue2
consumer1
consumer2
consumer3

常见exchange类型

1、Fanout广播

2、Direct路由

3、Topic话题

Fanout Exchange

Fanout Exchange会将接收到的消息路由到每一个跟其绑定的queue

fanout Exchange发送消息图解:

publisher
fanout exchange
fanout.queue
fanout.queue
consumer1
consumer2

其中fount Exchange的名称为itcast.fanout

代码实现

1、配置类

@Configuration
public class FanoutConfig {

    /**
     * 说明交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange("itcase.fanout");
    }

    /**
     * 声明队列
     * @return
     */
    @Bean
    public Queue fanoutQueue1() {
        return new Queue("fanout.queue1");
    }

    @Bean
    public Queue fanoutQueue2() {
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定交换机和队列
     * @param fanoutQueue1
     * @param fanoutExchange
     * @return
     */
    @Bean
    public Binding bindingFanoutExchange1(Queue fanoutQueue1, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
    }

    @Bean
    public Binding bindingFanoutExchange2(Queue fanoutQueue2, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
    }

}

2、监听者

@RabbitListener(queues = "fanout.queue1")
public void listenerFanoutQueue1(String message) {
    System.out.println("fanout queue1接收到的消息 : " + message);
}

@RabbitListener(queues = "fanout.queue2")
public void listenerFanoutQueue2(String message) {
    System.out.println("fanout queue2接收到的消息 : " + message);
}

3、发送测试

@Test
void listenFanoutExchange() {
    String queueName = "itcase.fanout";
    String message = "dear all hello queue";
    rabbitTemplate.convertAndSend(queueName, "", message);
    System.out.println("发送消息结束");
}

Direct Exchange

Direct Exchange会根据规则路由发送到指定的Queue。

每一个Queue都与Exchange设置BindingKey,发布者发送消息时,指定消息的RoutingKey,Exchange将消息路由到BindingKey与消息的RoutingKey一致的队列

代码实现

1、监听者

@Component
public class SpringRabbitListener {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue1"),  // 队列名称
            exchange = @Exchange(name = "itcase.direct", type = ExchangeTypes.DIRECT), // 交换机的名称以及类型
            key = {"red", "blue"}
    ))
    public void listenDirectQueue1(String message) {
        System.out.println("queue1 接收到的 " + message);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "direct.queue2"),  // 队列名称
            exchange = @Exchange(name = "itcase.direct", type = ExchangeTypes.DIRECT), // 交换机的名称以及类型
            key = {"red", "yellow"}
    ))
    public void listenDirectQueue2(String message) {
        System.out.println("queue2 接收到的 " + message);
    }
}

2、发送测试

@Test
void sendDirectExchange() {
    String queueName = "itcase.direct";
    String message = "dear all hello direct";
    rabbitTemplate.convertAndSend(queueName, "red", message);
    System.out.println("发送消息结束");
}

Topic Exchange

Topic Exchange与Direct Exchange类似,区别在于routingKey必须是多个单词的类别,并以.分割

Queue与Exchange指定BindingKey时可以使用通配符

#代指0个或多个单词

*代指一个单词

代码实现

1、监听者

@Component
public class SpringRabbitListener {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue1"),
            exchange = @Exchange(name = "itcase.topic", type = ExchangeTypes.TOPIC),
            key = "china.#"
    ))
    public void ListenTopicQueue1(String message) {
        System.out.println("queue1 接收到的 " + message);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "topic.queue2"),
            exchange = @Exchange(name = "itcase.topic", type = ExchangeTypes.TOPIC),
            key = "#.news"
    ))
    public void ListenTopicQueue2(String message) {
        System.out.println("queue2 接收到的 " + message);
    }
}

2、发送

@Test
void sendTopicExchange() {
    String queueName = "itcase.topic";
    String message = "dear all hello topic china weather ";
    rabbitTemplate.convertAndSend(queueName, "china.weather", message);
    System.out.println("发送消息结束");
}

消息转化器

SpringAMQP支持发送对象,由于MQ底层只能发送字节,所以需要序列化。而Spring本身自带的序列化是比较长占内存空间传输速度慢且不易读

引入Maven依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.14.2</version>
</dependency>

注意:如果你使用的spring boot较高的版本,spring boot内部已经有了jackson-dataformat-xml依赖了,无需导入该依赖否则启动不了项目

1、配置类

@Bean
public MessageConverter jsonMessageConverter() {
    return new Jackson2JsonMessageConverter();
}
@Bean
public Queue messageConverter() {
    return new Queue("converter.queue");
}

注意引入的是org.springframework.amqp.support.converter.MessageConverter;的包

2、监听者

@Component
public class SpringRabbitListener {

    @RabbitListener(queues = "converter.queue")
    public void listenMessageConverter(Map<String, String> message) {
        System.out.println("map value is " + message);
    }
}

3、发送

 @Test
void sendMessageConverter() {
    String routingKey = "converter.queue";
    Map<String, String> map = new HashMap<>();
    map.put("hello", "world");
    rabbitTemplate.convertAndSend(routingKey,  map);
    System.out.println("发送消息结束");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值