芋道 Spring Boot 消息队列 RocketMQ 入门

点击上方“芋道源码”,选择“设为星标

做积极的人,而不是积极废人!

源码精品专栏

 

摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/RocketMQ/ 「芋道源码」欢迎转载,保留摘要,谢谢!

  • 1. 概述

  • 2. RocketMQ-Spring

  • 3. 快速入门

  • 4. 批量发送消息

  • 5. 定时消息

  • 6. 消费重试

  • 7. 广播消费

  • 8. 顺序消息

  • 9. 事务消息

  • 10. 接入阿里云的消息队列 RocketMQ

  • 666. 彩蛋


本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-31 目录。

原创不易,给点个 Star 嘿,一起冲鸭!

1. 概述

如果胖友还没了解过分布式消息队列 Apache RocketMQ ,建议先阅读下艿艿写的 《芋道 RocketMQ 极简入门》 文章。虽然这篇文章标题是安装部署,实际可以理解成《一文带你快速入门 RocketMQ》,哈哈哈。

考虑这是 RocketMQ 如何在 Spring Boot 整合与使用的文章,所以还是简单介绍下 RocketMQ 是什么?

FROM 《消息中间件 Apache RocketMQ》

RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。同时,广泛应用于多个领域,包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即时通信、移动应用、手游、视频、物联网、车联网等。

具有以下特点:

  • 能够保证严格的消息顺序

  • 提供丰富的消息拉取模式

  • 高效的订阅者水平扩展能力

  • 实时的消息订阅机制

  • 亿级消息堆积能力

ps: Metaq 3.0 版本改名,产品名称改为 RocketMQ

在本文中,我们会比 《芋道 RocketMQ 极简入门》 提供更多的生产者 Producer 和消费者 Consumer 的使用示例。例如说:

  • Producer 三种发送消息的方式。

  • Producer 发送顺序消息,Consumer 顺序消费消息。

  • Producer 发送定时消息。

  • Producer 批量发送消息。

  • Producer 发送事务消息。

  • Consumer 广播和集群消费消息。

胖友你就说,艿艿是不是很良心。????

2. RocketMQ-Spring

RocketMQ-Spring 项目,RocketMQ 对 Spring 的集成支持。主要有两方面的功能:

  • 功能一:支持 Spring Message 规范,方便开发者从其它 MQ 快速切换到 RocketMQ 。

  • 功能二:帮助开发者在 Spring Boot 中快速集成 RocketMQ 。

我们先一起了解下功能一。对于大多数国内的开发者,相信对 Spring Message 是比较陌生的,包括艿艿自己。所幸艿艿是一个专业的收藏家,无意中看到有篇文章介绍了 RocketMQ-Spring 在这块的设计上的想法:

FROM 《我用这种方法在 Spring 中实现消息的发送和消息》

Spring Messaging 是 Spring Framework 4 中添加的模块,是Spring 与消息系统集成的一个扩展性的支持。它实现了从基于 JmsTemplate 的简单的使用 JMS 接口到异步接收消息的一整套完整的基础架构,Spring AMQP 提供了该协议所要求的类似的功能集。在与 Spring Boot 的集成后,它拥有了自动配置能力,能够在测试和运行时与相应的消息传递系统进行集成。

单纯对于客户端而言,Spring Messaging 提供了一套抽象的 API 或者说是约定的标准,对消息发送端和消息接收端的模式进行规定,不同的消息中间件提供商可以在这个模式下提供自己的 Spring 实现:

  • 在消息发送端,需要实现的是一个 XXXTemplate 形式的 Java Bean ,结合 Spring Boot 的自动化配置选项提供多个不同的发送消息方法;

  • 在消息的消费端,是一个 XXXMessageListener 接口(实现方式通常会使用一个注解来声明一个消息驱动的 POJO ),提供回调方法来监听和消费消息,这个接口同样可以使用 Spring Boot 的自动化选项和一些定制化的属性。

如果有兴趣深入的了解 Spring Messaging 及针对不同的消息产品的使用,推荐阅读这个文件。参考 Spring Messaging 的既有实现, RocketMQ 的 spring-boot-starter 中遵循了相关的设计模式,并结合 RocketMQ 自身的功能特点提供了相应的 API(如,顺序,异步和事务半消息等)。

这样一撸,是不是清晰多了。简单来说,RocketMQ-Spring 就是基于 Spring Message 来实现 RocketMQ 的发送端和接收端。

我们再一起了解下功能二。比较好理解,就是提供了 RocketMQ 的 spring-boot-starter 功能,实现 RocketMQ 的自动化配置。

不过,这里艿艿还是想弱弱吐槽一句,RocketMQ 的官方 spring-boot-starter 真的有点出的太晚了。如下是整理的时间轴:

  • 2014-08 Spring Boot 1 正式发布。

  • 2018-03 Spring Boot 2 正式发布。

  • 2018-12 RocketMQ 团队发布 RocketMQ 集成到 Spring Boot 的解决方案,并且提供了中文文档。

3. 快速入门

示例代码对应仓库:lab-31-rocketmq-demo 。

本小节,我们先来对 RocketMQ-Spring 做一个快速入门,实现 Producer 三种发送消息的方式的功能,同时创建一个 Consumer 消费消息。

考虑到一个应用既可以使用生产者 Producer ,又可以使用消费者 Consumer ,所以示例就做成一个 lab-31-rocketmq-demo 项目。

3.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>lab-31-rocketmq-demo</artifactId>

    <dependencies>
        <!-- 实现对 RocketMQ 的自动化配置 -->
        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>

        <!-- 方便等会写单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

具体每个依赖的作用,胖友自己认真看下艿艿添加的所有注释噢。

3.2 应用配置文件

在 resources 目录下,创建 application.yaml 配置文件。配置如下:

# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
  name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  # Producer 配置项
  producer:
    group: demo-producer-group # 生产者分组
    send-message-timeout: 3000 # 发送消息超时时间,单位:毫秒。默认为 3000 。
    compress-message-body-threshold: 4096 # 消息压缩阀值,当消息体的大小超过该阀值后,进行消息压缩。默认为 4 * 1024B
    max-message-size: 4194304 # 消息体的最大允许大小。。默认为 4 * 1024 * 1024B
    retry-times-when-send-failed: 2 # 同步发送消息时,失败重试次数。默认为 2 次。
    retry-times-when-send-async-failed: 2 # 异步发送消息时,失败重试次数。默认为 2 次。
    retry-next-server: false # 发送消息给 Broker 时,如果发送失败,是否重试另外一台 Broker 。默认为 false
    access-key: # Access Key ,可阅读 https://github.com/apache/rocketmq/blob/master/docs/cn/acl/user_guide.md 文档
    secret-key: # Secret Key
    enable-msg-trace: true # 是否开启消息轨迹功能。默认为 true 开启。可阅读 https://github.com/apache/rocketmq/blob/master/docs/cn/msg_trace/user_guide.md 文档
    customized-trace-topic: RMQ_SYS_TRACE_TOPIC # 自定义消息轨迹的 Topic 。默认为 RMQ_SYS_TRACE_TOPIC 。
  # Consumer 配置项
  consumer:
    listeners: # 配置某个消费分组,是否监听指定 Topic 。结构为 Map<消费者分组, <Topic, Boolean>> 。默认情况下,不配置表示监听。
      test-consumer-group:
        topic1: false # 关闭 test-consumer-group 对 topic1 的监听消费
  • 在 rocketmq 配置项,设置 RocketMQ 的配置,对应 RocketMQProperties 配置类。

  • RocketMQ-Spring RocketMQAutoConfiguration 自动化配置类,实现 RocketMQ 的自动配置,创建相应的 Producer 和 Consumer 。

  • rocketmq.name-server 配置项,设置 RocketMQ Namesrv 地址。如果多个,使用逗号分隔。

  • rocketmq.producer 配置项,一看就知道是 RocketMQ Producer 所独有。

    • group 配置,生产者分组。

    • retry-next-server 配置,发送消息给 Broker 时,如果发送失败,是否重试另外一台 Broker 。默认为 false 。如果胖友使用多主 Broker 的情况下,需要设置 true ,这样才会在发送消息失败时,重试另外一台 Broker 。

    • 其它配置,一般默认即可。

  • rocketmq.consumer 配置项,一看就知道是 RocketMQ Consumer 所独有。

    • listener 配置,配置某个消费分组,是否监听指定 Topic 。结构为 Map<消费者分组, <Topic, Boolean>> 。默认情况下,不配置表示监听。一般情况下,只有我们在想不监听消费某个消费分组的某个 Topic 时,才需要配 listener 配置。

3.3 空

不存在 3.3 ,目录标记错了。咳咳咳

3.4 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

// Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

3.5 Demo01Message

在 cn.iocoder.springboot.lab31.rocketmqdemo.message 包下,创建 Demo01Message 消息类,提供给当前示例使用。代码如下:

// Demo01Message.java

public class Demo01Message {

    public static final String TOPIC = "DEMO_01";

    /**
     * 编号
     */
    private Integer id;

    // ... 省略 set/get/toString 方法

}
  • TOPIC 静态属性,我们设置该消息类对应 Topic 为 "DEMO_01" 。

3.6 Demo01Producer

在 cn.iocoder.springboot.lab31.rocketmqdemo.producer 包下,创建 Demo01Producer 类,它会使用 RocketMQ-Spring 封装提供的 RocketMQTemplate ,实现三种发送消息的方式。代码如下:

// Demo01Producer.java

@Component
public class Demo01Producer {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public SendResult syncSend(Integer id) {
        // 创建 Demo01Message 消息
        Demo01Message message = new Demo01Message();
        message.setId(id);
        // 同步发送消息
        return rocketMQTemplate.syncSend(Demo01Message.TOPIC, message);
    }

    public void asyncSend(Integer id, SendCallback callback) {
        // 创建 Demo01Message 消息
        Demo01Message message = new Demo01Message();
        message.setId(id);
        // 异步发送消息
        rocketMQTemplate.asyncSend(Demo01Message.TOPIC, message, callback);
    }

    public void onewaySend(Integer id) {
        // 创建 Demo01Message 消息
        Demo01Message message = new Demo01Message();
        message.setId(id);
        // oneway 发送消息
        rocketMQTemplate.sendOneWay(Demo01Message.TOPIC, message);
    }

}
  • 三个方法,对应三个 RocketMQ 发送消息的方式,分别调用 RocketMQTemplate 提供的 #syncSend(...) 和 #asyncSend(...) 以及 #sendOneWay(...) 方法。

我们来简单聊下 RocketMQTemplate 类,它继承 Spring Messaging 定义的 AbstractMessageSendingTemplate 抽象类,以达到融入 Spring Messaging 体系中。

在 RocketMQTemplate 中,会创建一个 RocketMQ DefaultMQProducer 生产者 producer ,所以 RocketMQTemplate 后续的各种发送消息的方法,都是使用它。???? 当然,因为 RocketMQTemplate 的封装,所以我们可以像使用 Spring Messaging 一样的方式,进行消息的发送,而无需直接使用 RocketMQ 提供的 Producer 发送消息。

对于胖友来说,可能最关心的是,消息 Message 是怎么序列化的。我们来看看 RocketMQUtil#convertToRocketMessage(...) 方法的代码:

// RocketMQTemplate.java

public SendResult syncSend(String destination, Object payload, long timeout) {
    Message<?> message = MessageBuilder.withPayload(payload).build(); // <X>
    // ... 省略其它代码
}

//  RocketMQUti.java

public static org.apache.rocketmq.common.message.Message convertToRocketMessage(
    MessageConverter messageConverter, String charset,
    String destination, org.springframework.messaging.Message<?> message) {
    Object payloadObj = message.getPayload();
    byte[] payloads;
    try {
        if (null == payloadObj) {
            throw new RuntimeException("the message cannot be empty");
        }
        // 如果是 String 类型,则直接获得其 byte[] 内容。
        if (payloadObj instanceof String) {
            payloads = ((String)payloadObj).getBytes(Charset.forName(charset));
        // 如果是 byte[] 类型,则直接使用即可
        } else if (payloadObj instanceof byte[]) {
            payloads = (byte[])message.getPayload();
        // 如果是复杂对象类型,则使用 MessageConverter 进行转换成字符串,然后再获得字符串的 byte[] 内容。
        } else {
            String jsonObj = (String)messageConverter.fromMessage(message, payloadObj.getClass());
            if (null == jsonObj) {
                throw new RuntimeException(String.format(
                    "empty after conversion [messageConverter:%s,payloadClass:%s,payloadObj:%s]",
                    messageConverter.getClass(), payloadObj.getClass(), payloadObj));
            }
            payloads = jsonObj.getBytes(Charset.forName(charset));
        }
    } catch (Exception e) {
        throw new RuntimeException("convert to RocketMQ message failed.", e);
    }
    // 转换成 RocketMQ Message
    return getAndWrapMessage(destination, message.getHeaders(), payloads);
}
  • 在 <X> 处,RocketMQTemplate 会通过 Spring Messaging 的 MessageBuilder 将我们传入的消息 payload 转换成 Spring Messaging 的 Message 消息对象。

  • RocketMQUtil#convertToRocketMessage(...) 的代码,胖友自己看下艿艿添加的注释,进行下理解。因为我们一般消息都是复杂对象类型,所以会采用 MessageConverter 进行转换。RocketMQ-Spring 的默认使用 MappingJackson2MessageConverter 或 MappingFastJsonMessageConverter ,即使用 JSON 格式序列化和反序列化 Message 消息内容。为什么是这两个 MessageConverter ,胖友可以自己看看 RocketMQ-Spring 的 MessageConverterConfiguration 配置类。

3.7 空

不存在 3.7 ,目录标记错了。咳咳咳

3.8 Demo01Consumer

在 cn.iocoder.springboot.lab31.rocketmqdemo.consumer 包下,创建 Demo01Consumer 类,实现 Rocket-Spring 定义的 RocketMQListener 接口,消费消息。代码如下:

// Demo01Consumer.java

@Component
@RocketMQMessageListener(
        topic = Demo01Message.TOPIC,
        consumerGroup = "demo01-consumer-group-" + Demo01Message.TOPIC
)
public class Demo01Consumer implements RocketMQListener<Demo01Message> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void onMessage(Demo01Message message) {
        logger.info("[onMessage][线程编号:{} 消息内容:{}]", Thread.currentThread().getId(), message);
    }

}
  • 在类上,添加了 @RocketMQMessageListener 注解,声明消费的 Topic 是 "DEMO_01" ,消费者分组是 "demo01-consumer-group-DEMO_01" 。一般情况下,我们建议一个消费者分组,仅消费一个 Topic 。这样做会有

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security 是一个强大且灵活的认证和授权框架,用于保护 Spring Boot 应用程序的安全性。下面是一个简单的入门指南,帮助你开始使用 Spring Security: 1. 添加 Spring Security 依赖:在你的项目的 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 创建一个 Spring Security 配置类:创建一个类并注解为 `@Configuration`,这个类将用于配置 Spring Security。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public").permitAll() // 允许访问公共资源 .anyRequest().authenticated() // 其他请求需要认证 .and() .formLogin() // 启用表单登录 .and() .logout() // 启用注销功能 .and() .csrf().disable(); // 禁用 CSRF(跨站请求伪造)保护 } } ``` 在上述示例中,我们配置了一些基本的安全规则。可以自定义更多的规则来满足你的需求,比如配置自定义登录页面、添加用户角色等。 3. 添加用户认证:在上述配置类中,可以添加一个内存用户存储来进行简单的用户认证。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("admin") .password("{noop}password") // 使用 {noop} 前缀表示不加密密码 .roles("ADMIN"); } } ``` 在上述示例中,我们创建了一个用户名为 "admin"、密码为 "password"、角色为 "ADMIN" 的用户。 这只是 Spring Security 的入门指南,你可以进一步学习如何使用数据库存储用户信息、配置角色权限等。希望这些信息对你有所帮助!如果你有更多问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值