React Streams规范是响应式编程领域的一项重要标准,它为异步流处理提供了统一的接口和语义。这套规范最初由Reactive Streams组织制定,后来被纳入Java 9的java.util.concurrent.Flow API中,并成为响应式编程库如Project Reactor、RxJava等的基础。
React Streams规范的核心目标是解决背压(Backpressure)问题,即在生产者(Publisher)和消费者(Subscriber)之间平衡数据流速的机制。传统的数据流处理中,当生产者的生产速度超过消费者的处理能力时,会导致数据积压、内存溢出等问题。React Streams通过一套明确的契约关系,使得消费者能够动态地控制数据流速,从而实现高效、可靠的异步流处理。
React Streams规范定义了四个核心接口:Publisher(发布者)、Subscriber(订阅者)、Subscription(订阅关系)和Processor(处理器)。这些接口构成了响应式编程的基础模型,下面我们将逐一深入分析每个组件。
Publisher是数据流的源头,负责生产数据项并推送给订阅者。在React Streams规范中,Publisher是一个泛型接口,定义如下:
public interface Publisher<T> {
void subscribe(Subscriber<? super T> subscriber);
}
Publisher的核心职责是:
一个正确的Publisher实现需要遵循以下规则:
在实际应用中,Publisher有多种实现形式:
冷发布者(Cold Publisher):只有当有Subscriber订阅时才开始生产数据,每个Subscriber获取完整独立的数据流。例如从数据库读取数据。
热发布者(Hot Publisher):无论是否有Subscriber订阅都会生产数据,Subscriber只能获取订阅后产生的数据。例如股票价格实时推送。
单值发布者:只发布一个数据项或错误后就结束的Publisher。
空发布者:不发布任何数据项,直接调用onComplete的Publisher。
Publisher必须尊重Subscriber通过Subscription.request(n)方法发出的数据请求量。这意味着:
这种机制确保了Subscriber不会被超出其处理能力的数据淹没,从而实现了背压控制。
当Publisher遇到不可恢复的错误时,应该:
// 自定义一个简单的Publisher实现
class SimplePublisher<T> implements Publisher<T> {
private final Iterable<T> data;
public SimplePublisher(Iterable<T> data) {
this.data = data;
}
@Override
public void subscribe(Subscriber<? super T> subscriber) {
// 创建Subscription并传递给Subscriber
subscriber.onSubscribe(new SimpleSubscription(subscriber, data));
}
static class SimpleSubscription<T> implements Subscription {
private final Subscriber<? super T> subscriber;
private final Iterator<T> iterator;
private volatile boolean cancelled = false;
SimpleSubscription(Subscriber<? super T> subscriber, Iterable<T> data) {
this.subscriber = subscriber;
this.iterator = data.iterator();
}
@Override
public void request(long n) {
if (n <= 0) {
subscriber.onError(new IllegalArgumentException(
"请求数量必须大于0"));
return;
}
long emitted = 0;
while (emitted < n && !cancelled && iterator.hasNext()) {
subscriber.onNext(iterator.next());
emitted++;
}
if (!cancelled && !iterator.hasNext()) {
subscriber.onComplete();
}
}
@Override
public void cancel() {
cancelled = true;
}
}
}
Subscriber是数据流的消费者,接收并处理Publisher推送的数据。Subscriber接口定义如下:
public interface Subscriber<T> {
void onSubscribe(Subscription subscription);
void onNext(T item);
void onError(Throwable throwable);
void onComplete();
}
Subscriber的生命周期方法:
一个正确的Subscriber实现必须遵循以下规则:
Subscriber通过Subscription.request(n)方法来控制数据流速,常见的策略包括:
请求一次:在onSubscribe中请求固定数量的数据
public void onSubscribe(Subscription s) {
s.request(10); // 请求10个数据项
}
按需请求:在处理完一个数据项后再请求下一个
public void onNext(T item) {
// 处理数据
subscription.request(1); // 再请求1个
}
批量请求:维护一个缓冲区,当缓冲区低于阈值时批量请求
private static final int BATCH_SIZE = 32;
private int count = 0;
public void onNext(T item) {
// 处理数据
if (++count % BATCH_SIZE == 0) {
subscription.request(BATCH_SIZE);
}
}
Subscriber应该:
// 一个完整的Subscriber实现示例
class SimpleSubscriber<T> implements Subscriber<T> {
private Subscription subscription;
private final int bufferSize;
public SimpleSubscriber(int bufferSize) {
this.bufferSize = bufferSize;
}
@Override
public void onSubscribe(Subscription subscription) {
this.subscription = subscription;
// 初始请求一个缓冲区的数据量
subscription.request(bufferSize);
}
@Override
public void onNext(T item) {
try {
// 处理接收到的数据
System.out.println("处理数据: " + item);
// 模拟处理耗时
Thread.sleep(100);
// 每处理完bufferSize/2个数据就补充请求
if (random.nextInt(bufferSize) < bufferSize/2) {
subscription.request(bufferSize/2);
}
} catch (Exception e) {
subscription.cancel();
onError(e);
}
}
@Override
public void onError(Throwable t) {
System.err.println("处理出错: " + t.getMessage());
t.printStackTrace();
}
@Override
public void onComplete() {
System.out.println("数据处理完成");
}
}
Subscription是Publisher和Subscriber之间的契约,代表了二者之间的订阅关系。接口定义如下:
public interface Subscription {
void request(long n);
void cancel();
}
Subscription的核心职责:
request(long n)
cancel()
正确的Subscription实现应该:
Subscription是背压控制的关键媒介,它需要:
复杂的Subscription可能会实现以下特性:
class AdvancedSubscription<T> implements Subscription {
private final Subscriber<? super T> subscriber;
private final Executor executor;
private final Queue<T> dataQueue;
private long requested = 0;
private volatile boolean cancelled = false;
private boolean isProducing = false;
public AdvancedSubscription(Subscriber<? super T> subscriber,
Executor executor,
Iterable<T> data) {
this.subscriber = subscriber;
this.executor = executor;
this.dataQueue = new ConcurrentLinkedQueue<>();
data.forEach(dataQueue::offer);
}
@Override
public void request(long n) {
if (n <= 0) {
executor.execute(() ->
subscriber.onError(new IllegalArgumentException(
"请求数量必须大于0")));
return;
}
// 累积请求量
long newRequested = addRequest(n);
// 如果从0变为有请求,开始生产
if (newRequested == n) { // 之前没有待处理请求
scheduleDelivery();
}
}
private synchronized long addRequest(long n) {
if (requested == Long.MAX_VALUE) {
return Long.MAX_VALUE; // 已经处于无限请求模式
}
long newRequested = requested + n;
if (newRequested < 0) { // 溢出
newRequested = Long.MAX_VALUE;
}
requested = newRequested;
return requested;
}
private synchronized long takeRequested(int deliver) {
if (requested == Long.MAX_VALUE) {
return Long.MAX_VALUE;
}
requested -= deliver;
return requested;
}
private void scheduleDelivery() {
executor.execute(() -> {
if (isProducing || cancelled) {
return;
}
isProducing = true;
try {
int delivered = 0;
while (!cancelled && (requested > 0 || requested == Long.MAX_VALUE)
&& !dataQueue.isEmpty()) {
T item = dataQueue.poll();
if (item == null) {
break;
}
subscriber.onNext(item);
delivered++;
if (requested != Long.MAX_VALUE && delivered % 10 == 0) {
takeRequested(delivered);
delivered = 0;
}
}
takeRequested(delivered);
if (!cancelled) {
if (dataQueue.isEmpty()) {
subscriber.onComplete();
} else if (requested > 0 || requested == Long.MAX_VALUE) {
// 还有数据和请求,继续调度
scheduleDelivery();
}
}
} catch (Exception e) {
if (!cancelled) {
subscriber.onError(e);
}
} finally {
isProducing = false;
}
});
}
@Override
public void cancel() {
cancelled = true;
dataQueue.clear();
}
}
Processor同时扮演Publisher和Subscriber的双重角色,用于在数据流处理链中实现转换、过滤等操作。接口定义如下:
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {
}
Processor的主要用途:
常见的Processor实现模式包括:
Processor需要同时处理上下游的背压:
正确的Processor实现应该:
class TransformProcessor<T, R> implements Processor<T, R> {
private final Function<? super T, ? extends R> transformer;
private Subscription upstreamSubscription;
private Subscriber<? super R> downstreamSubscriber;
private final Queue<T> inputBuffer = new ConcurrentLinkedQueue<>();
private final Queue<R> outputBuffer = new ConcurrentLinkedQueue<>();
private long upstreamRequested = 0;
private long downstreamRequested = 0;
private volatile boolean upstreamCompleted = false;
private volatile boolean cancelled = false;
private Throwable error = null;
public TransformProcessor(Function<? super T, ? extends R> transformer) {
this.transformer = transformer;
}
// Subscriber方法实现
@Override
public void onSubscribe(Subscription subscription) {
this.upstreamSubscription = subscription;
if (downstreamSubscriber != null) {
downstreamSubscriber.onSubscribe(new Subscription() {
@Override
public void request(long n) {
if (n <= 0) {
onError(new IllegalArgumentException(
"请求数量必须大于0"));
return;
}
synchronized (TransformProcessor.this) {
long newRequested = downstreamRequested + n;
if (newRequested < 0) { // 溢出
newRequested = Long.MAX_VALUE;
}
downstreamRequested = newRequested;
}
requestFromUpstream();
deliverToDownstream();
}
@Override
public void cancel() {
cancelled = true;
upstreamSubscription.cancel();
inputBuffer.clear();
outputBuffer.clear();
}
});
}
}
@Override
public void onNext(T item) {
if (cancelled) {
return;
}
inputBuffer.offer(item);
tryTransform();
deliverToDownstream();
}
@Override
public void onError(Throwable t) {
error = t;
upstreamCompleted = true;
if (downstreamSubscriber != null && outputBuffer.isEmpty()) {
downstreamSubscriber.onError(t);
}
}
@Override
public void onComplete() {
upstreamCompleted = true;
if (downstreamSubscriber != null && outputBuffer.isEmpty()) {
downstreamSubscriber.onComplete();
}
}
// Publisher方法实现
@Override
public void subscribe(Subscriber<? super R> subscriber) {
this.downstreamSubscriber = subscriber;
if (upstreamSubscription != null) {
subscriber.onSubscribe(/* ... */); // 见上面的onSubscribe实现
}
}
private void tryTransform() {
while (!inputBuffer.isEmpty() && !cancelled) {
T item = inputBuffer.poll();
try {
R transformed = transformer.apply(item);
outputBuffer.offer(transformed);
synchronized (this) {
if (upstreamRequested != Long.MAX_VALUE) {
upstreamRequested--;
}
}
} catch (Exception e) {
onError(e);
return;
}
}
requestFromUpstream();
}
private void requestFromUpstream() {
long toRequest;
synchronized (this) {
if (upstreamRequested <= 0 && !cancelled) {
toRequest = downstreamRequested - upstreamRequested;
if (toRequest > 0) {
upstreamRequested += toRequest;
}
} else {
toRequest = 0;
}
}
if (toRequest > 0) {
upstreamSubscription.request(toRequest);
}
}
private void deliverToDownstream() {
if (downstreamSubscriber == null || cancelled) {
return;
}
while (downstreamRequested > 0 && !outputBuffer.isEmpty()) {
R item = outputBuffer.poll();
downstreamSubscriber.onNext(item);
synchronized (this) {
if (downstreamRequested != Long.MAX_VALUE) {
downstreamRequested--;
}
}
}
if (upstreamCompleted && outputBuffer.isEmpty()) {
if (error != null) {
downstreamSubscriber.onError(error);
} else {
downstreamSubscriber.onComplete();
}
}
}
}
现代响应式编程库如Project Reactor和RxJava都基于React Streams规范构建:
Project Reactor:
RxJava:
实现高效React Streams组件时需要考虑:
测试React Streams组件时需要注意:
React Streams规范为异步流处理提供了标准化的契约,通过Publisher、Subscriber、Subscription和Processor四个核心接口,构建了一套完整的响应式编程模型。理解这些组件的职责和交互方式,对于构建高效、可靠的异步系统至关重要。
在实际应用中,通常不需要从头实现这些接口,而是使用成熟的响应式编程库(如Project Reactor或RxJava)。然而,深入理解这些底层规范,有助于更好地使用这些高级库,并在需要自定义操作时做出正确的设计决策。
React Streams规范的真正价值在于其背压处理机制,这使得生产者和消费者能够协同工作,避免数据溢出或资源浪费。这种流量控制能力是构建弹性、响应式系统的关键所在。