首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 觀察者模式 (Observer Pattern) 完整實戰:JDK 內建 API、自定義事件總線、Spring 事件、RxJava 響應式對比

     編輯:Java 相關知識

前言

觀察者模式 (發布-訂閱) 是解耦業務邏輯、實現事件驅動架構的核心模式。Java 提供 java.beans 內建支援,Spring 提供 ApplicationEvent,現代響應式編程用 RxJava/Project Reactor。本文從 JDK 原生 API 入手,逐層遞進至企業級事件總線與響應式流,附完整代碼對比。

一、JDK 內建觀察者 API (java.beans)

1.1 核心類

  • PropertyChangeListener:監聽器介面,單方法 propertyChange(PropertyChangeEvent)
  • PropertyChangeSupport:被觀察者委託類,管理監聽器註冊/移除/通知
  • PropertyChangeEvent:事件對象,攜帶 propertyName、oldValue、newValue

1.2 標準實現範例

public class Domain {
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private String name;

    public String getName() { return name; }
    public void setName(String name) {
        String old = this.name;
        this.name = name;
        pcs.firePropertyChange("name", old, name); // 通知所有監聽器
    }

    public void addPropertyChangeListener(PropertyChangeListener l) { pcs.addPropertyChangeListener(l); }
    public void removePropertyChangeListener(PropertyChangeListener l) { pcs.removePropertyChangeListener(l); }
}

public class NameLogger implements PropertyChangeListener {
    @Override public void propertyChange(PropertyChangeEvent evt) {
        if ("name".equals(evt.getPropertyName())) {
            System.out.printf("名稱變更: %s -> %s%n", evt.getOldValue(), evt.getNewValue());
        }
    }
}

// 使用
Domain d = new Domain();
d.addPropertyChangeListener(new NameLogger());
d.setName("Alice"); // 控制台輸出: 名稱變更: null -> Alice

1.3 優缺點

優點缺點
零依賴、JDK 內建、線程安全僅支援屬性變更事件、同步阻塞通知、無異步/背壓機制

二、自定義事件總線 (同步/異步、泛型、優先級)

public interface EventListener<T> { void onEvent(T event); }

public final class EventBus {
    private final Map<Class<?>, List<EventListener<?>>> listeners = new ConcurrentHashMap<>();
    private final ExecutorService asyncExecutor = Executors.newCachedThreadPool();

    public <T> void subscribe(Class<T> eventType, EventListener<T> listener) {
        listeners.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()).add(listener);
    }

    public <T> void publish(T event) {
        List<EventListener<?>> list = listeners.get(event.getClass());
        if (list != null) {
            for (EventListener<?> l : list) {
                // 同步調用
                @SuppressWarnings("unchecked") EventListener<T> tl = (EventListener<T>) l;
                tl.onEvent(event);
            }
        }
    }

    public <T> void publishAsync(T event) {
        asyncExecutor.submit(() -> publish(event));
    }
}

// 使用
class UserRegistered { String username; }
EventBus bus = new EventBus();
bus.subscribe(UserRegistered.class, e -> System.out.println("發送歡迎郵件: " + e.username));
bus.publishAsync(new UserRegistered("Alice"));

三、Spring 應用事件

@Component
public class EmailService {
    @EventListener // 自動訂閱
    public void sendWelcome(UserRegisteredEvent event) {
        emailSender.send(event.getEmail(), "歡迎註冊");
    }

    @EventListener(condition = "#event.vip") // SpEL 條件過濾
    public void sendVipGift(UserRegisteredEvent event) { ... }
}

// 發布
@Autowired ApplicationEventPublisher publisher;
publisher.publishEvent(new UserRegisteredEvent("alice@test.com", true));
  • 支援 @Async 異步、@TransactionalEventListener 事務綁定 (提交後發布)
  • 整合 Spring 生命週期、依賴注入、條件過濾、異常處理

四、RxJava 3 / Project Reactor 響應式流對比

特性JDK PropertyChange自定義 EventBusSpring EventsRxJava / Reactor
異步/非阻塞❌✅ (手動)✅ (@Async)✅ 原生 (Scheduler)
背壓❌❌❌✅ (Flowable/Flux)
操作符 (map/filter/flatMap)❌❌❌✅ 豐富
錯誤處理/重試❌手動有限✅ 完善
適用場景簡單 UI 綁定、Bean 屬性監聽輕量級微服務內部解耦Spring 生態業務事件高吞吐、流處理、複雜編排

五、選型建議

  1. Swing/JavaFX UI、簡單 Bean 監聽 → JDK PropertyChangeListener
  2. 非 Spring 微服務、輕量級模組解耦 → 自定義 EventBus (可引入 Guava EventBus / MBassador)
  3. Spring Boot 應用業務事件 → ApplicationEventPublisher + @EventListener (首選)
  4. 高併發流處理、複雜事件編排、需要背壓 → Project Reactor (Spring WebFlux) 或 RxJava 3

六、總結

觀察者模式核心在於發布者與訂閱者解耦。Java 生態提供從同步阻塞到響應式非阻塞的完整譜系,根據併發量、延遲要求、技術棧、團隊熟悉度選擇最合適層級,避免過度設計。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved