RocketMQ Consumer接收消息流程

 这节介绍Consumer接收消息的流程,分为Pull和Push模式。

1. 初始化

 上一节讲Rebalance时提到,Consumer接受客户端有两种方式:

  1. Broker发现客户端列表有变化,通知所有Consumer执行Rebalance
  2. Consumer定时每20秒自动执行Rebalance

其中1.的通知到达Consumer后,会立即触发Rebalance,然后会重置2.的定时器等待时间。二者最后通知Consumer的方式为

  1. Push模式:当有新的Queue分配给客户端时,会新包装一个PullRequest,用于后续自动拉取消息,具体到DefaultMQPushConsumerImpl的executePullRequestImmediately方法
  2. Pull模式:回调DefaultMQPullConsumerImpl的MessageQueueListener有Queue发生改变
2. Push模式

 executePullRequestImmediately的内容为:

public void executePullRequestImmediately(final PullRequest pullRequest) {
    this.mQClientFactory.getPullMessageService().executePullRequestImmediately(pullRequest);
}

即将PullRequest对象传给了PullMessageService的executePullRequestImmediately方法:

public void executePullRequestImmediately(final PullRequest pullRequest) {
    try {
        this.pullRequestQueue.put(pullRequest);
    } catch (InterruptedException e) {
        log.error("executePullRequestImmediately pullRequestQueue.put", e);
    }
}

PullMessageService的结构如下:

file

内部维护着一个LinkedBlockingQueue属性pullRequestQueue,用于存储待处理的PullRequest;还有一个ScheduledExecutorService,用于延期处理PullRequest。具体流程如下:

file

  1. RebalanceImpl调用DefaultMQPushConsumerImpl的executePullRequestImmediately方法,传入PullRequest
  2. DefaultMQPushConsumerImpl内部调用PullMessageService的executePullRequestImmediately方法,该方法会把传入的PullRequest对象放到LinkedBlockingQueue中进行存储,等待后续处理。
  3. PullMessageService会循环从队列中出队一个PullRequest,并调用自身的pullMessage用于后续处理。该动作会从MQClientInstance中选择对应的客户端实例DefaultMQPushConsumerImpl,并委托给它的pullMessage方法。
  4. DefaultMQPushConsumerImpl会先判断当前请求是否满足条件,如果不满足条件,会调用PullMessage的executePullRequestLater方法,将当前请求延后处理。如果满足条件,会封装一个PullCallback对象用于处理异步消息,并调用PullAPIWrapper异步请求Broker拉取消息。

从上面的过程可以看出,Push模式内部还是客户端主动去拉取的,即所谓的封装拉模式以实现推模式,简单示意图如下:

file

内部通过PullMessageService循环的从PullRequest对应MessageQueue中主动拉取数据。

2.1. DefaultMQPushConsumerImpl.pullMessage(PullRequest)

 该方法用于完成从MessageQueue拉取消息的过程,主要过程如下:

file

  1. 判断该MessageQueue对应的PullRequest是否已经标记为drop,如果是则直接返回
  2. 进行一系列的检查,如果检查不通过,则等待一定时间后再放回PullMessageService的待处理队列中,主要是通过PullMessageService中的ScheduledExecutorService来做到延迟执行,涉及的情况包括:
    1. 如果客户端未准备就绪(DefaultMQPushCOnsumerImpl执行start后status为RUNNING),则延迟PULL_TIME_DELAY_MILLS_WHEN_EXCEPTION(3000)后再放回PullMessage的队列中
    2. 如果是暂停状态,则延迟PULL_TIME_DELAY_MILLS_WHEN_SUSPEND(1000)后再放回PullMessageService的等待队列中
    3. 如果缓存的消息数大于配置的拉取线程数阈值(默认1000),则等待PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL(50)后再返回等待队列中处理
    4. 如果缓存的消息大小大于配置的拉取大小阈值(默认100M),则等待PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL(50)后再返回等待队列中处理
    5. 缓存的数据offset相差的偏移量超过设定值(默认2000),则等待PULL_TIME_DELAY_MILLS_WHEN_FLOW_CONTROL(50)后再返回等待队列中处理
    6. 如果没有订阅MessageQueue对应的topic,则等待PULL_TIME_DELAY_MILLS_WHEN_EXCEPTION(3000)后再返回队列中处理
  3. 包装PullCallback对象,并调用PullAPIWrapper发起异步请求拉取消息

上面通过PullAPIWrapper收到结果后会将结果包装为PullResult对象并回调PullCallback。PullCallback和PullResult的定义如下:

public interface PullCallback {
    void onSuccess(final PullResult pullResult);
    
    void onException(final Throwable e);
}

public class PullResult {
    private final PullStatus pullStatus;//请求状态
    private final long nextBeginOffset;//Broker返回的下一次开始消费的offset
    private final long minOffset;
    private final long maxOffset;
    private List<MessageExt> msgFoundList;//消息列表,一次请求返回一批消息
}

下面为pullMessage方法处理异步返回结果的流程:

file

  1. 如果请求失败,则等待PULL_TIME_DELAY_MILLS_WHEN_EXCEPTION(3000)后再放回PullMessageService的待处理队列中;处理成功则进入2.
  2. 调用PullAPIWrapper对结果进行预处理
  3. 根据请求状态进行处理
    1. 有新消息(FOUND)
      1. 设置PullRequest下次开始消费的起始位置为PullResult的nextBeginOffset
      2. 如果结果列表为空则不延迟,立马放到PullMessageService的待处理队列中,否则进入3
      3. 将PullResult中的结果List放入ProcessQueue的缓存中,并通知ConsumeMessageService处理
      4. 将该PullRequest放回待处理队列中等待再次处理,如果有设置拉取的间隔时间,则等待该时间后再翻到队列中等待处理,否则直接放到队列中等待处理
    2. 没有新消息(NO_NEW_MSG)
      1. 设置PullRequest下次开始消费的起始位置为PullResult的nextBeginOffset
      2. 如果缓存的待消费消息数为0,则更新offset存储
      3. 将PullRequest立马放到PullMessageService的待处理队列中
    3. 没有匹配的消息(NO_MATCHED_MSG)
      1. 设置PullRequest下次开始消费的起始位置为PullResult的nextBeginOffset
      2. 如果缓存的待消费消息数为0,则更新offset存储
      3. 将PullRequest立马放到PullMessageService的待处理队列中
    4. 不合法的偏移量(OFFSET_ILLEGAL)
      1. 设置PullRequest下次开始消费的起始位置为PullResult的nextBeginOffset
      2. 标记该PullRequset为drop
      3. 10s后再更新并持久化消费offset;再通知Rebalance移除该MessageQueue

 下面先介绍下ProcessQueue,这里只标识几个相关的属性:

public class ProcessQueue {
    private final ReadWriteLock lockTreeMap = new ReentrantReadWriteLock();
    //缓存的待消费消息,按照消息的起始offset排序
    private final TreeMap</*消息的起始offset*/Long, MessageExt> msgTreeMap = new TreeMap<Long, MessageExt>();
    //缓存的待消费消息数量
    private final AtomicLong msgCount = new AtomicLong();
    //缓存的待消费消息大小
    private final AtomicLong msgSize = new AtomicLong();
    private final Lock lockConsume = new ReentrantLock();
    /**
     * A subset of msgTreeMap, will only be used when orderly consume
     */
    private final TreeMap<Long, MessageExt> consumingMsgOrderlyTreeMap = new TreeMap<Long, MessageExt>();
    private final AtomicLong tryUnlockTimes = new AtomicLong(0);
    private volatile long queueOffsetMax = 0L;
    private volatile boolean dropped = false;
    //最近执行pull的时间
    private volatile long lastPullTimestamp = System.currentTimeMillis();
    //最近被客户端消费的时间
    private volatile long lastConsumeTimestamp = System.currentTimeMillis();
    private volatile boolean locked = false;
    private volatile long lastLockTimestamp = System.currentTimeMillis();
    //当前是否在消费,用于顺序消费模式,对并行消费无效
    private volatile boolean consuming = false;
    private volatile long msgAccCnt = 0;
}

ProcessQueue展示了MessageQueue的消费情况。上面提到,发起pull请求后如果有数据,会先放到ProcessQueue的缓存中,即msgTreeMap属性,因而缓存的消息会按照消息的起始offset被排序存储。通过ProcessQueue可以查看MessageQueue当前的处理情况,ProcessQueue还用于辅助实现顺序消费。

2.2 ConsumeMessageService

 异步返回的消息内容将交给ConsumeMessageService处理,ConsumeMessageService是个接口,方法定义如下:

public interface ConsumeMessageService {
    void start();

    void shutdown();

    void updateCorePoolSize(int corePoolSize);

    void incCorePoolSize();

    void decCorePoolSize();

    int getCorePoolSize();

    ConsumeMessageDirectlyResult consumeMessageDirectly(final MessageExt msg, final String brokerName);

    void submitConsumeRequest(
        final List<MessageExt> msgs,
        final ProcessQueue processQueue,
        final MessageQueue messageQueue,
        final boolean dispathToConsume);
}

通过定义可见,要求实现类提供异步处理的功能。内部提供的实现类有:

file

ConsumeMessageConcurrentlyService:并行消费;ConsumeMessageOrderlyService:顺序消费,这里重点看ConsumeMessageConcurrentlyService。异步请求后会将拉取的新消息列表交给submitConsumeRequest方法处理,如下:

file

该方法会将传入的消息列表分装为一个ConsumeRequest,并提到到线程池中等待处理。如果传入的消息列表长度超过设定值(默认为1),则会分多个批处理。

 在介绍消费具体过程之前先回顾客户端启动流程的Demo,接收消息的写法如下:

public class Consumer {

    public static void main (String[] args) throws InterruptedException, MQClientException {

        // 实例化消费者
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer ("GroupTest");

        // 设置NameServer的地址
        consumer.setNamesrvAddr ("localhost:9876");

        // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息
        consumer.subscribe ("TopicTest", "*");
        // 注册回调实现类来处理从broker拉取回来的消息
        consumer.registerMessageListener (new MessageListenerConcurrently () {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage (List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.printf ("%s Receive New Messages: %s %n", Thread.currentThread ().getName (), msgs);
                // 标记该消息已经被成功消费
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        // 启动消费者实例
        consumer.start ();
        System.out.printf ("Consumer Started.%n");
    }
}

其中注册了一个MessageListenerConcurrently,该类将用于用户端处理消息。

 回过来看ConsumeRequest,该类实现了Runnable接口,会在run方法完成主要的处理工作,主要动作为:

  1. 调用DefaultMQPushConsumerImpl.executeHookBefore执行前置hook动作
  2. 调用MessageListenerConcurrently.consumeMessage通知用户端处理消息,即上面demo内容,会返回处理结果ConsumeConcurrentlyStatus
  3. 调用DefaultMQPushConsumerImpl.executeHookAfter执行后置hook动作
  4. ConsumeMessageConcurrentlyService.processConsumeResult根据ConsumeConcurrentlyStatus执行收尾动作
2.2.1. MessageListenerConcurrently.consumeMessage

 用户真正接收消息并执行处理动作的地方,需要返回ConsumeConcurrentlyStatus告知框架处理结果。这里在方法里最好不要做耗时长的任务,快速处理后返回给框架结果,避免消息堆积在线程池中。可以将消息内容复制一遍后再放到线程池中进行分发处理。

2.2.2. ConsumeMessageConcurrentlyService.processConsumeResult

 该方法主要在用户消费完数据后进行收尾动作,过程如下:

file

ConsumerRequest在run方法的开始处,实例化了一个ConsumeConcurrentlyContext对象,用于后续传递内容,该定义为:

public class ConsumeConcurrentlyContext {
    private final MessageQueue messageQueue;
    //重试的延迟级别,-1:不重试;0:由broker控制;>0由客户端控制
    private int delayLevelWhenNextConsume = 0;
    //消息列表最后一个正常消费的消息索引号
    private int ackIndex = Integer.MAX_VALUE;
}

其中ackIndex表示最后一个正常消费的消息索引号(0从开始,0~ackIndex为正常消费),该位置后的消息表示没法正常消费。该值由用户端控制,可以通过ackIndex来控制需要重发的消息。

 ackIndex默认值为Integer.MAX_VALUE,如果为该值则认为所有消息正常消费,不存在错误。上面流程中统计成功和失败也是根据ackIndex来判断的,对于ackIndex后的消息,如果是集群消费模式,则会先尝试发送回broker,由broker控制重试时机;如果重试失败,会收集这些失败的消息,延迟5秒后再调用一次ConsumeMessageService.submitConsumeRequest让用户端再次处理。最后会将处理成功的消息从ProcessQueue中移除,更新缓存,然后将q消费的偏移量记录下来,等待后台线程同步到broker或者本地。

 综合上面的介绍,Push模式下的处理流程大致如下:

file

Push模式通过PullMessageService循环从监听的MessageQueue中以Pull模式拉取消息,并分发给用户注册的MesageListenerConsurrently对象处理,完了之后会自动处理消息的重试,offset更新等动作,从而模拟消息从Broker端主动推动过来。

2. Pull模式

 同Push模式一样,Pull模式的触发也是通过Rebalance,如下:

file

同开头提及的一样,会回调DefaultMQPullConsumerImpl的MessageQueueListener有Queue发生改变。

 系统提供了MQPullConsumerScheduleService,可以定时以Pull模式拉取消息,并将结果通知MessageQueueListener,内部的实现为:

class MessageQueueListenerImpl implements MessageQueueListener {
    @Override
    public void messageQueueChanged(String topic, Set<MessageQueue> mqAll, Set<MessageQueue> mqDivided) {//mqAll该topic下的所有q,mqDivided该实例分配到的q
        MessageModel messageModel =
            MQPullConsumerScheduleService.this.defaultMQPullConsumer.getMessageModel();
        switch (messageModel) {
            case BROADCASTING:
                MQPullConsumerScheduleService.this.putTask(topic, mqAll);//通知该topic下的监听器,最新的所有q
                break;
            case CLUSTERING:
                MQPullConsumerScheduleService.this.putTask(topic, mqDivided);//通知该topic下的监听器,该实例分配的q
                break;
            default:
                break;
        }
    }
}

putTask会将分配到的新的MessageQueue包装为一个PullTaskImpl,PullTaskImpl实现了Runnable,会在后台一直执行;而将不属于自己处理的MessageQueue对应的PullTaskImpl停掉。PullTaskImpl会查找该MessageQueue所监听topic对应的处理类PullTaskCallback,调用doPullTask,将具体动作让用户处理。

 MQPullConsumerScheduleService的例子为:

public class PullScheduleService {

    public static void main(String[] args) throws MQClientException {
        final MQPullConsumerScheduleService scheduleService = new MQPullConsumerScheduleService("GroupName1");

        scheduleService.setMessageModel(MessageModel.CLUSTERING);
        scheduleService.registerPullTaskCallback("TopicTest", new PullTaskCallback() {//注册topic的监听器

            @Override
            public void doPullTask(MessageQueue mq, PullTaskContext context) {
                MQPullConsumer consumer = context.getPullConsumer();
                try {

                    long offset = consumer.fetchConsumeOffset(mq, false);
                    if (offset < 0)
                        offset = 0;

                    PullResult pullResult = consumer.pull(mq, "*", offset, 32);
                    System.out.printf("%s%n", offset + "\t" + mq + "\t" + pullResult);
                    switch (pullResult.getPullStatus()) {
                        case FOUND:
                            break;
                        case NO_MATCHED_MSG:
                            break;
                        case NO_NEW_MSG:
                        case OFFSET_ILLEGAL:
                            break;
                        default:
                            break;
                    }
                    consumer.updateConsumeOffset(mq, pullResult.getNextBeginOffset());//上报消费的offset,消费完后要主动上报

                    context.setPullNextDelayTimeMillis(100);//设置下一次触发间隔
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        scheduleService.start();
    }
}

 也可以自己手动执行pull,如下面的例子:

public class PullConsumer {
    private static final Map<MessageQueue, Long> OFFSE_TABLE = new HashMap<MessageQueue, Long>();

    public static void main(String[] args) throws MQClientException {
        DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("please_rename_unique_group_name_5");

        consumer.start();

        Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicTest1");
        for (MessageQueue mq : mqs) {
            System.out.printf("Consume from the queue: %s%n", mq);
            SINGLE_MQ:
            while (true) {
                try {
                    PullResult pullResult =
                        consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
                    System.out.printf("%s%n", pullResult);
                    putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
                    switch (pullResult.getPullStatus()) {
                        case FOUND:
                            break;
                        case NO_MATCHED_MSG:
                            break;
                        case NO_NEW_MSG:
                            break SINGLE_MQ;
                        case OFFSET_ILLEGAL:
                            break;
                        default:
                            break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        consumer.shutdown();
    }

    private static long getMessageQueueOffset(MessageQueue mq) {
        Long offset = OFFSE_TABLE.get(mq);
        if (offset != null)
            return offset;

        return 0;
    }

    private static void putMessageQueueOffset(MessageQueue mq, long offset) {
        OFFSE_TABLE.put(mq, offset);
    }

}

 相较于Push模式,Pull模式则需要用户自己控制消息的重试,offset更新等动作。下面附上该部分当时源码阅读过程做的笔记简图:

file

更多原创内容请搜索微信公众号:啊驼(doubaotaizi)

<think> 首先,用户的问题是关于如何使用Spring Cloud Stream的StreamBridge在RocketMQ中进行消息发送和接收的方法。用户参考了几个引用,我需要基于这些引用以及系统指令来构建回答。 系统指令回顾: - 所有行内数学表达式必须使用$...$格式(但这个问题是关于编程的,可能不需要数学)。 - 独立公式用$$...$$,但这里可能不适用。 - LaTeX语法正确(同样,可能不适合)。 - 使用中文回答。 - 生成相关问题。 - 在引用的段落末尾自然地添加引用标识,例如[^1]。 - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠(基于提供的引用)。 用户提供的引用: - [^1]:介绍RocketMQ普通消费等,包括使用原生API发送消息的代码示例。 - [^2]:Spring Cloud Alibaba发送广播消息RocketMQ,使用streamBridge.send方法。 - [^3]:Spring Cloud Stream集成RocketMQ,使用函数式编程方式(弃用@EnableBinding等)。 - [^4]:Spring Cloud Stream 3.x操作RocketMQ的依赖和配置。 用户的问题焦点:如何使用StreamBridge在RocketMQ中发送和接收消息。 我的回答需要: 1. 结构化:一步步解释发送和接收的过程。 2. 引用相关部分:在末尾添加引用标识。 3. 使用中文。 4. 生成相关问题。 核心内容: - 发送消息:使用StreamBridge的send方法。 - 接收消息:使用函数式编程(如Consumer)来处理消息。 - 配置:需要在配置文件中设置绑定和RocketMQ参数。 从引用中提取关键信息: - [^2]:展示了streamBridge.send的使用:`streamBridge.send("producer-out-0", new SimpleMsg(...));`,绑定名称在配置中定义。 - [^3]:提到Spring Cloud Stream 3.1+使用函数式编程,弃用旧的注解。 - [^4]:提供依赖配置:spring-cloud-starter-stream-rocketmq。 步骤构建回答: 1. **介绍StreamBridge**:简要说明它是一个用于消息发送的工具。 2. **发送消息**:解释如何使用streamBridge.send,示例代码。 3. **接收消息**:解释如何定义消费者函数(Supplier或Consumer)。 4. **配置文件**:展示必要的配置(application.yml)。 5. **依赖配置**:列出所需的依赖。 6. **引用添加**:在相关部分添加[^n]。 7. **生成相关问题**:在结束时生成几个相关问题。 确保引用正确: - 引用[^2]是关于发送广播消息的。 - 引用[^3]是关于函数式编程集成的。 - 引用[^4]是关于依赖的。 - 在回答中,当提到具体点时,添加引用标识。 最终回答结构: - 开头:直接回答问题。 - 主体:分步骤发送和接收。 - 结尾:生成相关问题。 </think> ### RocketMQ使用StreamBridge发送和接收消息的方法 在Spring Cloud Stream 3.1及以上版本中,弃用了传统的`@EnableBinding`、`@Input`和`@Output`注解,改用函数式编程模型(Function、Supplier、Consumer)集成RocketMQ。`StreamBridge`是Spring Cloud Stream提供的工具类,用于动态发送消息。以下基于引用内容,分步解释如何使用`StreamBridge`实现消息的发送和接收。方法支持普通消息、广播消息等场景,需配合Spring Cloud Alibaba RocketMQ Starter实现[^3][^4]。 #### 步骤1: 添加依赖 在`pom.xml`中添加必要的依赖,包括Spring Boot Web、Rombok(可选)和Spring Cloud Stream RocketMQ Starter。引用[^4]提供了基础配置示例: ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> </dependencies> ``` 确保Spring Cloud Alibaba版本与Spring Boot兼容(例如,Spring Boot 2.7.x + Spring Cloud 2021.0.x)。 #### 步骤2: 配置绑定和RocketMQ参数 在`application.yml`中定义绑定名称和RocketMQ服务器地址。发送端使用`producer`绑定,接收端使用`consumer`绑定。引用[^2]和[^4]强调了配置的重要性: ```yaml spring: cloud: stream: bindings: # 发送绑定:定义生产者输出通道 producer-out-0: destination: test-topic # RocketMQ主题 content-type: application/json # 消息格式,支持JSON、文本等 # 接收绑定:定义消费者输入通道 consumer-in-0: destination: test-topic group: consumer-group # 消费者组名(用于广播或集群消费) rocketmq: binder: name-server: 127.0.0.1:9876 # RocketMQ NameServer地址 ``` - **关键点**: - `producer-out-0`是发送绑定的标准命名(`out`表示输出,`0`表示索引)。 - `consumer-in-0`是接收绑定的命名(`in`表示输入)。 - 支持广播消费:在`consumer-in-0`下添加`spring.cloud.stream.bindings.consumer-in-0.consumer.broadcast=true`[^2]。 #### 步骤3: 使用StreamBridge发送消息 在服务中注入`StreamBridge`实例,调用其`send`方法发送消息消息内容可以是对象(自动序列化)或字节数组。引用[^2]展示了发送广播消息的代码: ```java import org.springframework.cloud.stream.function.StreamBridge; import org.springframework.stereotype.Service; @Service public class MessageProducerService { private final StreamBridge streamBridge; public MessageProducerService(StreamBridge streamBridge) { this.streamBridge = streamBridge; } public void sendMessage(String payload) { // 发送消息到绑定名称"producer-out-0" boolean success = streamBridge.send("producer-out-0", payload); if (success) { System.out.println("消息发送成功"); } else { System.out.println("消息发送失败"); } } } ``` - **参数详解**: - 第一个参数:绑定名称(对应yml中的`producer-out-0`)。 - 第二个参数:消息体,支持自定义对象(如`SimpleMsg`,需实现序列化)。 - 返回值:`boolean`类型,表示发送是否成功。 - 支持延时消费:在消息头中添加延时级别(例如:`MessageBuilder.withPayload(payload).setHeader("DELAY", "3").build()`)。 #### 步骤4: 定义消费者接收消息 使用函数式编程模型定义消息消费者。创建一个`Consumer` Bean处理消息。引用[^3]和[^4]强调了Supplier/Consumer的用法: ```java import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import java.util.function.Consumer; @Component public class MessageConsumer { // 定义消费者:绑定名"consumer-in-0"对应yml配置 @Bean public Consumer<String> consumer-in-0() { return message -> { System.out.println("接收到的消息: " + message); // 添加业务逻辑,例如处理过滤消费(基于消息头或标签) }; } } ``` - **关键点**: - 方法名必须与yml中的绑定名称匹配(例如`consumer-in-0`)。 - 支持过滤消费:在yml中添加`spring.cloud.stream.rocketmq.bindings.consumer-in-0.consumer.subscription=tagA || tagB`过滤标签。 - 事务消息:需配合RocketMQ事务API实现,但通过`StreamBridge`发送时需在生产者端添加事务逻辑[^1]。 #### 完整示例流程 1. **启动应用**:Spring Boot会自动扫描`StreamBridge`和Consumer Bean。 2. **发送消息**:调用`MessageProducerService.sendMessage("Hello RocketMQ")`发送到主题`test-topic`。 3. **接收消息**:消费者打印消息内容,实现端到端通信。 - **性能注意**:默认使用异步发送,可配置重试机制(yml中添加`spring.cloud.stream.bindings.producer-out-0.producer.max-attempts=3`)。 此方法简化了RocketMQ集成,避免了原生API的复杂性,适用于微服务架构[^2][^3]。配置和代码基于引用内容整合,确保兼容Spring Cloud Stream 3.x[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值