Publisher เป็นผู้ให้ unbounded number of sequenced elements เผยแพร่ตาม demand ที่ได้รับจาก Subscribers Publisher<T> interface รับผิดชอบ publish elements ประเภท T และให้เมธอด subscribe() สำหรับ subscribers เชื่อมต่อ
public interface Publisher<T> {
public void subscribe(Subscriber<? super T> s);
}
กฎสำหรับ Publisher Interface
- จำนวน onNext() ทั้งหมดที่ Publisher ส่งให้ Subscriber ต้องน้อยกว่าหรือเท่ากับจำนวน elements ที่ Subscriber ขอผ่าน Subscription ตลอดเวลา
- Publisher อาจส่ง onNext() น้อยกว่าที่ขอ และจบ Subscription โดยเรียก onComplete() หรือ onError()
- onSubscribe(), onNext(), onError(), onComplete() ที่ส่งให้ Subscriber ต้องส่งแบบ serial (ลำดับชัดเจน)
- ถ้า Publisher ล้มเหลว ต้องส่งสัญญาณ onError()
- ถ้า Publisher สำเร็จ ต้องส่งสัญญาณ onComplete()
- ถ้า Publisher ส่ง onError() หรือ onComplete() ให้ Subscriber แล้ว Subscription ของ Subscriber ต้องถูก cancel
- เมื่อ terminal state ถูกส่งแล้ว (onError(), onComplete()) ห้ามมี signals เพิ่มเติม
- ถ้า Subscription ถูก cancel Subscriber ต้องหยุดรับ signals
- Publisher.subscribe() ต้องเรียก onSubscribe() บน Subscriber ที่ให้มา ก่อน signals อื่นๆ และคืนค่าปกติ ยกเว้น Subscriber เป็น null ต้องโยน NullPointerException
- Publisher.subscribe() อาจเรียกได้หลายครั้งกับ Subscriber คนละตัวทุกครั้ง
- Publisher อาจรองรับ multiple Subscribers และตัดสินใจว่าแต่ละ Subscription เป็น unicast หรือ multicast
Reactive Streams Specification
กฎเหล่านี้เป็นส่วนของ Reactive Streams Specification (java.util.concurrent.Flow) ที่มาตรฐาน化 asynchronous stream processing กับ non-blocking backpressure
Component Relationships
Publisher --subscribe()--> Subscriber
|
v
Subscription (1:1 with Subscriber)
|
|-- request(n) --> Publisher produces n items
|-- cancel() --> Stop production
Implementation Example
import java.util.concurrent.Flow.*;
public class SimplePublisher implements Publisher<Integer> {
private final Iterator<Integer> iterator;
SimplePublisher(int count) {
this.iterator = IntStream.rangeClosed(1, count).iterator();
}
@Override
public void subscribe(Subscriber<? super Integer> subscriber) {
subscriber.onSubscribe(new Subscription() {
@Override
public void request(long n) {
for (long i = 0; i < n && iterator.hasNext(); i++) {
subscriber.onNext(iterator.next());
}
if (!iterator.hasNext()) {
subscriber.onComplete();
}
}
@Override
public void cancel() {
// Cleanup if needed
}
});
}
}
Key Points
- Backpressure: Subscriber ควบคุม rate ผ่าน
request(n) - Asynchronous: ไม่บล็อก thread รอข้อมูล
- Non-blocking: Publisher ไม่รอ Subscriber process
- Error propagation: onError ส่งผ่าน chain
- Completion signal: onComplete แจ้งจบ stream