Project Reactor响应式编程简介

前言:Reactor 是一种事件驱动的高性能网络编程模型 ,主要用于处理高并发的网络 I/O 请求。其核心思想是通过一个或多个线程监听事件,并将事件分发给相应的处理程序,从而实现高效的并发处理。在响应式编程(如 Project Reactor )中,理解 发布(Publish)与订阅(Subscribe)、生产者(Producer)与消费者(Consumer) 的概念非常重要。它们是构建异步、非阻塞数据流的基础模型。


一、Reactor基本概念

1. 发布者(Publisher)

  • 是数据的提供方。

  • 在 Project Reactor 中,FluxMono 都实现了 Publisher<T> 接口。

  • 它不主动发送数据,而是等待被订阅后才开始发射数据。

类比:就像一个电台频道,在没有人收听时它不会"广播"内容,只有当有人打开收音机(订阅),才会开始播放节目。

java 复制代码
Flux<String> publisher = Flux.just("A", "B", "C"); // Publisher

2. 订阅者(Subscriber)

  • 是数据的接收方。

  • 实现 Subscriber<T> 接口,或者使用 .subscribe() 方法作为简化方式。

  • 订阅者会通过回调方法接收数据(onNext)、异常(onError)或完成信号(onComplete)。

java 复制代码
publisher.subscribe(
    data -> System.out.println("Received: " + data), // onNext
    err -> System.err.println("Error: " + err),      // onError
    () -> System.out.println("Done!")                // onComplete
);

3. 订阅(Subscription)

  • 是连接 PublisherSubscriber 的桥梁。

  • 每次调用 .subscribe() 都会创建一个新的 Subscription

  • 支持背压(backpressure)控制:消费者可以告诉生产者"我一次只能处理 N 个元素"。

java 复制代码
publisher.subscribe(new Subscriber<>() {
    private Subscription subscription;

    @Override
    public void onSubscribe(Subscription s) {
        this.subscription = s;
        subscription.request(1); // 请求第一个数据
    }

    @Override
    public void onNext(String t) {
        System.out.println("Got: " + t);
        subscription.request(1); // 继续请求下一个
    }

    @Override
    public void onError(Throwable t) {
        t.printStackTrace();
    }

    @Override
    public void onComplete() {
        System.out.println("Completed");
    }
});

二、生产者和消费者模型(Producer/Consumer)

角色 描述
生产者(Producer) 提供数据流的一方,即 Publisher(如 Flux, Mono
消费者(Consumer) 接收并处理数据的一方,即 Subscriber
  • 数据从生产者流向消费者。

  • 这种模型支持异步非阻塞的数据传输。

  • 可以通过 背压机制 控制流量,避免消费者被过量数据淹没。


三、Reactor 中的发布与订阅流程

java 复制代码
[Publisher] --> (onSubscribe) --> [Subscriber]
     ↓
   (request)
     ↓
[Publisher emits data via onNext]
     ↓
[Subscriber receives data]
     ↓
[Eventually onComplete or onError]

流程说明:

  1. 订阅建立

    • 调用 .subscribe() 后,Publisher 会调用 onSubscribe(Subscription)
  2. 请求数据

    • Subscriber 调用 subscription.request(n) 表示希望接收 n 个数据。
  3. 数据发射

    • Publisher 发射数据项,调用 onNext(T)
  4. 结束或错误

    • 成功结束:调用 onComplete()

    • 出错:调用 onError(Throwable)


四、实际应用举例

示例:模拟生产者和消费者的协作(带背压)

java 复制代码
Flux.range(1, 100)
    .subscribe(new Subscriber<>() {
        private Subscription subscription;
        private int count = 0;

        @Override
        public void onSubscribe(Subscription s) {
            this.subscription = s;
            subscription.request(5); // 初始请求5个数据
        }

        @Override
        public void onNext(Integer integer) {
            System.out.println("Consuming: " + integer);
            count++;
            if (count % 5 == 0) {
                subscription.request(5); // 每消费5个再请求5个
            }
        }

        @Override
        public void onError(Throwable throwable) {
            throwable.printStackTrace();
        }

        @Override
        public void onComplete() {
            System.out.println("All items consumed!");
        }
    });

五、常见误区

错误理解 正确理解
Flux.just(...) 会立即发射数据 不会,除非有订阅者才会发射
Flux 是热源(Hot) 默认是冷源(Cold),每次订阅都会重新开始
subscribe() 返回值无关紧要 可用于取消订阅(返回 Disposable
所有操作符都是同步的 很多操作符是异步的,比如 flatMap, delayElements

六、总结

概念 说明
Publisher 数据源,如 FluxMono
Subscriber 数据消费者,实现 onNext, onError, onComplete
Subscription 控制数据流动的接口,支持背压
生产者/消费者模型 数据从生产者流向消费者,由订阅驱动
背压(Backpressure) 消费者可以控制生产者的发射速率
冷流 vs 热流 冷流每次订阅都从头开始;热流共享数据流(如 ConnectableFlux

如果你正在使用 Spring WebFluxRSocketKafka Streams 或其他响应式框架,理解这些核心概念将帮助你更好地设计和调试异步系统。