Spring 技巧:Apache RocketMQ 入门

127 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情

运行 Apache RocketMQ

为了使用 Apache RocketMQ,您需要按照RocketMQ快速入门中的步骤进行操作。本期 Spring Tips 介绍了 Apache RocketMQ,它最初是在阿里巴巴内部开发和使用的一项技术,并在11/11(中国著名的销售假期,有点像美国的“网络星期一”或“黑色星期五”)中得到验证. 有点像,但更大。2019 年,阿里巴巴(仅此一家,不涉及其他电子商务引擎)在 24 小时内赚取了近 400 亿美元。这需要通过可以扩展以满足需求的方式发送数万亿条消息。RocketMQ 是他们唯一可以信任的东西。

运行 Apache RocketMQ 时需要使用 Java 8。(当然,在编写连接到 Apache RocketMQ 的 Spring 应用程序时,您可以使用任何版本的 Java。)我使用 SDK Manager(“SDKman”—)sdk切换到适当的 Java 版本。

sdk use java 8.0.242.hs-adpt

如果尚未安装,这将安装一个可用的版本。完成后,您将需要运行 NameServer。

${ROCKETMQ_HOME}/bin/mqnamesrv

然后您需要运行 Broker 本身。

${ROCKETMQ_HOME}/bin/mqbroker -n localhost:9876

如果你想使用基于 SQL 的过滤,你需要在 broker 的配置中添加一个属性,$ROCKETMQ_HOME/conf/broker.conf然后告诉 RocketMQ 使用那个配置。

enablePropertyFilter = true

我使用这样的脚本来启动所有内容。

export JAVA_HOME=$HOME/.sdkman/candidates/java/8.0.242.hs-adpt
${ROCKETMQ_HOME}/bin/mqnamesrv &  
${ROCKETMQ_HOME}/bin/mqbroker -n localhost:9876 -c ${ROCKETMQ_HOME}/conf/broker.conf

从 Java 代码使用 Apache RocketMQ

让我们看一个使用 Spring Boot 自动配置和RocketMQTemplate.

为了使用它,您需要在Spring Initializr上创建一个新项目。我用最新版本的 Java 生成了一个新项目,然后确保包含Lombok. 我们还需要 Apache RocketMQ 客户端和适当的 Spring Boot 自动配置:

<dependency>  
<groupId>org.apache.rocketmq</groupId>  
<artifactId>rocketmq-spring-boot-starter</artifactId>  
<version>2.0.4</version>  
</dependency>

自动配置将创建一个到正在运行的 Apache RocketMQ 代理的连接,由某些属性通知。

rocketmq.name-server=127.0.0.1:9876  
rocketmq.producer.group=greetings-producer-group

第一个属性name-server告诉应用程序 Apache RocketMQ 名称服务器所在的位置。然后,名称服务器知道代理所在的位置。您还需要为生产者和消费者指定一个组。在这里,我们使用greetings-producer-group.

package com.example.producer;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.Message;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.support.MessageBuilder;import java.time.Instant;@RequiredArgsConstructor
@SpringBootApplication
public class ProducerApplication {    @Bean
    ApplicationListener<ApplicationReadyEvent> ready(RocketMQTemplate template) {
        return event -> {            var now = Instant.now();
            var destination = "greetings-topic";            for (var name : "Tammie,Kimly,Josh,Rob,Mario,Mia".split(",")) {                var payload = new Greeting("Hello @ " + name + " @ " + now.toString());
                var messagePostProcessor = new MessagePostProcessor() {                    @Override
                    public Message<?> postProcessMessage(Message<?> message) {
                        var headerValue = Character.toString(name.toLowerCase().charAt(0));
                        return MessageBuilder
                            .fromMessage(message)
                            .setHeader("letter", headerValue)
                            .build();
                    }
                };
                template.convertAndSend(destination, payload, messagePostProcessor);
            }
        };
    }    public static void main(String[] args) {
        SpringApplication.run(ProducerApplication.class, args);
    }
}@Data
@AllArgsConstructor
@NoArgsConstructor
class Greeting {
    private String message;
}

这是一个简单的 for 循环,处理每个名称,创建一个新Greeting对象,然后使用 将RocketMQTemplate负载发送到 Apache RocketMQ 主题,greetings-topicRocketMQTemplate在这里,我们使用了接受 a 的对象的重载MessagePostProcessor。这是一个回调,我们可以在其中转换将要发送出去的MessagePostProcessorSpring Framework对象。Message在此示例中,我们贡献了一个标头值,letter它包含名称的第一个字母。我们将在消费者中使用它。

让我们看看消费者。从 Spring Initializr 生成一个新的 Spring Boot 应用程序,并确保添加 Apache RocketMQ 自动配置。您还需要为application.properties客户端指定名称服务器。

自动配置支持定义 implement 的 bean RocketMQListener<T>,其中T是消费者将接收的有效负载的类型。在这种情况下,有效负载是Greeting.

package com.example.consumer;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Service;import static org.apache.rocketmq.spring.annotation.SelectorType.SQL92;@SpringBootApplication
public class ConsumerApplication {    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}@Data
@AllArgsConstructor
@NoArgsConstructor
class Greeting {
    private String message;
}@Log4j2
@Service
@RocketMQMessageListener(
    topic = "greetings-topic",
    consumerGroup = "simple-group"
)
class SimpleConsumer implements RocketMQListener<Greeting> {    @Override
    public void onMessage(Greeting greeting) {
        log.info(greeting.toString());
    }
}

在此示例中,SimpleConsumer仅记录来自 Apache RocketMQ 主题的所有传入消息greetings-topic。在这里,消费者将处理关于该主题的每条消息。 让我们看看另一个不错的特性——选择器——它让我们有选择地处理传入的消息。让我们用两个新的替换现有的 RocketMQ 侦听器。每一个都将使用与 SQL92 兼容的谓词来确定是否应该处理传入的消息。letter一个侦听器仅处理标头匹配mk或 的消息t。另一个只匹配letter标头匹配的那些 j

@Log4j2
@Service
@RocketMQMessageListener(
    topic = "greetings-topic",
    selectorExpression = " letter = 'm' or letter = 'k' or letter = 't' ",
    selectorType = SQL92,
    consumerGroup = "sql-consumer-group-mkt"
)
class MktSqlSelectorConsumer implements RocketMQListener<Greeting> {    @Override
    public void onMessage(Greeting greeting) {
        log.info("'m', 'k', 't': " + greeting.toString());
    }
}
@Log4j2
@Service
@RocketMQMessageListener(
    topic = "greetings-topic",
    selectorExpression = " letter = 'j' ",
    selectorType = SQL92,
    consumerGroup = "sql-consumer-group-j"
)
class JSqlSelectorConsumer implements RocketMQListener<Greeting> {    @Override
    public void onMessage(Greeting greeting) {
        log.info("'j': " + greeting.toString());
    }
}

Apache RocketMQ 还支持许多其他功能(除了在 24 小时内处理数万亿条消息!)它可以在磁盘上存储长尾消息,而不会降低性能。它支持消息、事务、批处理等的序列化(排序)。它甚至支持计划消息——仅在特定时间间隔后传递的消息。