定義對象間一對多依賴,當一個對象(Subject)狀態變化,所有依賴者(Observer)自動收到通知並更新。
public interface Subject {
void register(Observer o);
void unregister(Observer o);
void notifyObservers();
Object getUpdate(Observer o);
}
public interface Observer {
void update();
void setSubject(Subject s);
}
public class Topic implements Subject {
private final List observers = new CopyOnWriteArrayList<>();
private String message;
private final Object lock = new Object();
@Override public void register(Observer o) {
if (o == null) throw new NullPointerException();
observers.addIfAbsent(o);
}
@Override public void unregister(Observer o) { observers.remove(o); }
@Override public void notifyObservers() {
List snapshot;
synchronized (lock) {
if (message == null) return; // 無更新
snapshot = new ArrayList<>(observers);
}
snapshot.forEach(Observer::update); // 無鎖通知
}
@Override public Object getUpdate(Observer o) { return message; }
public void post(String msg) {
synchronized (lock) {
this.message = msg;
}
notifyObservers();
}
}
public class Subscriber implements Observer {
private final String name;
private Subject topic;
public Subscriber(String name) { this.name = name; }
@Override public void update() {
String msg = (String) topic.getUpdate(this);
System.out.println(name + (msg == null ? ":: 無新消息" : ":: 收到 → " + msg));
}
@Override public void setSubject(Subject s) { this.topic = s; }
}
public class Demo {
public static void main(String[] args) {
Topic topic = new Topic();
Observer o1 = new Subscriber("觀察者-1");
Observer o2 = new Subscriber("觀察者-2");
topic.register(o1); topic.register(o2);
o1.setSubject(topic); o2.setSubject(topic);
topic.post("第一條消息");
topic.post("第二條消息");
}
}
@Deprecated(since="9")Observable 是類而非接口,單繼承限制;setChanged() 受保護,需繼承才能用
// 1. 定義事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Long orderId;
public OrderCreatedEvent(Object source, Long orderId) { super(source); this.orderId = orderId; }
public Long getOrderId() { return orderId; }
}
// 2. 發布
@Component
public class OrderService {
@Autowired ApplicationEventPublisher publisher;
public void create() {
Long id = 100L;
publisher.publishEvent(new OrderCreatedEvent(this, id));
}
}
// 3. 監聽
@Component
public class InventoryListener {
@EventListener
public void handle(OrderCreatedEvent event) {
System.out.println("庫存扣減:訂單 " + event.getOrderId());
}
@EventListener(condition = "#event.orderId > 1000")
public void handleBig(OrderCreatedEvent event) { /* 大單特殊處理 */ }
}
// 4. 異步
@EnableAsync
@EventListener @Async
public void asyncHandle(OrderCreatedEvent event) { ... }
優勢:解耦、支持異步、SpEL 條件過濾、有序 @Order、事務綁定 @TransactionalEventListener。
PublishSubject subject = PublishSubject.create();
// 訂閱者 1
subject.subscribe(msg -> System.out.println("訂閱者1: " + msg));
// 訂閱者 2(僅接收含 "error" 的消息)
subject.filter(msg -> msg.contains("error"))
.subscribe(msg -> System.out.println("錯誤流: " + msg));
// 發布
subject.onNext("正常日誌");
subject.onNext("error: 連接超時");
subject.onComplete();
優勢:操作符豐富、背壓支持、線程調度、組合變換。
| 場景 | 推薦方案 |
|---|---|
| 簡單解耦、無框架依賴 | 自定義接口 / Guava EventBus |
| Spring Boot 微服務內部事件 | Spring ApplicationEvent |
| 跨服務異步解耦 | 消息隊列 + 領域事件 |
| 複雜流處理、背壓、合流分流 | RxJava / Reactor / Flow API |
| UI 綁定、Android LiveData | Lifecycle-aware Observable |