Java 观察者模式 3 种实现对比:原生接口 vs 自定义 vs Spring Event
·
Java观察者模式3种实现深度对比:从原生接口到Spring Event的工程实践
1. 观察者模式核心价值与应用场景
在软件系统中,对象间的状态依赖关系常常是复杂多变的。当订单状态变更需要通知物流系统、库存系统和用户端时,硬编码的调用方式会让系统耦合度急剧上升。观察者模式通过解耦主题对象与观察者,让状态变化能够自动传播到相关对象,这正是其核心价值所在。
典型应用场景包括 :
- 电商订单状态变更通知(支付成功、发货、签收等)
- 配置中心参数更新时的多系统同步
- 物联网设备状态监控与告警
- GUI事件处理机制(如按钮点击事件)
以订单系统为例,传统实现可能直接在订单状态变更方法中调用库存扣减、物流创建等方法。这种实现存在三个明显问题:
- 违反开闭原则,新增观察者需要修改主题类代码
- 调用链脆弱,任一观察者异常会影响整体流程
- 难以实现异步通知机制
观察者模式通过抽象解耦,完美解决了这些问题。下面我们通过具体代码示例,对比Java中三种典型的实现方式。
2. 原生JDK实现:java.util.Observable
Java标准库早在1.0版本就提供了观察者模式的实现基础,虽然现在已被标记为 @Deprecated ,但理解其设计仍有重要意义。
2.1 基础实现示例
// 被观察者(订单)
class OrderObservable extends Observable {
private String orderStatus;
public void setStatus(String newStatus) {
this.orderStatus = newStatus;
setChanged(); // 标记状态已变更
notifyObservers(newStatus); // 通知所有观察者
}
}
// 观察者(库存系统)
class InventoryObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("库存系统收到订单状态更新: " + arg);
// 实际业务逻辑:库存扣减、预留等
}
}
// 使用示例
public class JdkObserverDemo {
public static void main(String[] args) {
OrderObservable order = new OrderObservable();
order.addObserver(new InventoryObserver());
order.addObserver(new LogisticsObserver());
order.setStatus("PAID"); // 支付成功状态变更
}
}
2.2 优缺点分析
优势 :
- 开箱即用,无需额外依赖
- 线程安全的通知机制(
notifyObservers方法同步) - 提供
setChanged()方法控制通知条件
缺陷 :
Observable是类而非接口,限制了复用- 缺乏泛型支持,需要类型转换
- 通知顺序不可控
- Java 9后被标记为废弃
提示:在Java 9+环境中,建议使用
PropertyChangeListener替代,或选择其他实现方式
3. 自定义实现:灵活可控的观察者模式
当需要更精细控制时,自定义实现是更好的选择。下面展示一个支持泛型、事件过滤的增强版实现。
3.1 完整代码实现
// 事件对象基类
abstract class Event {
private long timestamp = System.currentTimeMillis();
// 可扩展公共事件属性
}
// 订单状态事件
class OrderStatusEvent extends Event {
private String orderId;
private String newStatus;
private String oldStatus;
// 构造器、getters省略
}
// 观察者接口
interface CustomObserver<T extends Event> {
void onEvent(T event);
default Predicate<T> eventFilter() {
return e -> true; // 默认接收所有事件
}
}
// 被观察者基类
class EventPublisher<T extends Event> {
private final List<CustomObserver<? super T>> observers = new CopyOnWriteArrayList<>();
public void register(CustomObserver<? super T> observer) {
observers.add(observer);
}
protected void notifyObservers(T event) {
observers.stream()
.filter(o -> o.eventFilter().test(event))
.forEach(o -> o.onEvent(event));
}
}
// 具体订单被观察者
class OrderPublisher extends EventPublisher<OrderStatusEvent> {
public void statusChanged(String orderId, String oldStatus, String newStatus) {
OrderStatusEvent event = new OrderStatusEvent(orderId, oldStatus, newStatus);
notifyObservers(event);
}
}
// 使用示例
class InventoryService implements CustomObserver<OrderStatusEvent> {
@Override
public void onEvent(OrderStatusEvent event) {
if ("SHIPPED".equals(event.getNewStatus())) {
System.out.println("库存系统: 订单已发货,释放预留库存");
}
}
@Override
public Predicate<OrderStatusEvent> eventFilter() {
return e -> !e.getNewStatus().equals(e.getOldStatus());
}
}
3.2 进阶特性对比
| 特性 | JDK Observable | 自定义实现 |
|---|---|---|
| 类型安全 | ❌ | ✅ 泛型支持 |
| 事件过滤 | ❌ | ✅ 灵活配置 |
| 异步通知 | ❌ | ✅ 可自由实现 |
| 观察者优先级 | ❌ | ✅ 可排序实现 |
| 生命周期管理 | 简单 | 完善 |
| 性能开销 | 低 | 中等(需权衡特性) |
工程实践建议 :
- 简单场景可使用
PropertyChangeSupport - 复杂事件系统推荐自定义实现
- 高频事件考虑引入事件总线(如Guava EventBus)
4. Spring Event:企业级解决方案
在Spring生态中,应用上下文的事件机制提供了开箱即用的观察者模式实现,特别适合分布式系统。
4.1 基本用法
// 定义事件(支持序列化)
public class OrderEvent extends ApplicationEvent {
private final String orderId;
private final String eventType;
public OrderEvent(Object source, String orderId, String eventType) {
super(source);
this.orderId = orderId;
this.eventType = eventType;
}
// getters...
}
// 监听器实现
@Component
class OrderEventListener {
@Async // 支持异步处理
@EventListener(condition = "#event.eventType == 'PAY_SUCCESS'")
public void handlePaymentSuccess(OrderEvent event) {
// 处理支付成功逻辑
}
@TransactionalEventListener(phase = AFTER_COMMIT)
public void handleAfterCommit(OrderEvent event) {
// 事务提交后处理
}
}
// 事件发布
@Service
class OrderService {
private final ApplicationEventPublisher publisher;
public void payOrder(String orderId) {
// 业务处理...
publisher.publishEvent(new OrderEvent(this, orderId, "PAY_SUCCESS"));
}
}
4.3 Spring Event高级特性
-
事务绑定事件 :
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) public void onOrderCompleted(OrderEvent event) { // 只在事务成功提交后执行 } -
条件过滤 :
@EventListener(condition = "#event.eventType matches '^PAY_.*'") -
异步处理 :
@Async @EventListener public void asyncHandle(OrderEvent event) { // 异步执行 } -
响应式支持 :
@EventListener public Mono<Void> reactiveHandle(OrderEvent event) { return Mono.fromRunnable(() -> { // 响应式处理 }); }
5. 三种实现对比与选型指南
5.1 功能对比表
| 特性 | JDK Observable | 自定义实现 | Spring Event |
|---|---|---|---|
| 学习成本 | 低 | 中 | 中 |
| 与框架集成 | 无 | 无 | 完美 |
| 事务支持 | ❌ | ❌ | ✅ |
| 异步支持 | ❌ | 手动实现 | ✅ |
| 分布式场景适用性 | ❌ | 有限 | ✅ |
| 性能开销 | 低 | 中 | 中高 |
| 扩展灵活性 | 低 | 高 | 中 |
5.2 选型决策树
graph TD
A[需要框架集成?] -->|是| B[Spring Event]
A -->|否| C{需要高级特性?}
C -->|是| D[自定义实现]
C -->|否| E[JDK Observable/PropertyChangeSupport]
实际项目经验 :
- 单体应用:Spring Event + 自定义简单事件
- 微服务架构:Spring Cloud Bus + 消息队列
- 高频事件:自定义实现 + Disruptor框架
- 跨语言系统:Apache Kafka事件总线
6. 性能优化与常见陷阱
6.1 性能优化点
-
观察者注册管理 :
// 使用CopyOnWriteArrayList替代普通ArrayList private final List<Observer> observers = new CopyOnWriteArrayList<>(); -
事件过滤前置 :
// 在通知前进行快速过滤 if (needsNotification(event)) { notifyObservers(event); } -
异步处理模式 :
executor.submit(() -> observers.forEach(o -> o.onEvent(event)));
6.2 常见问题与解决方案
问题1:内存泄漏
- 原因:观察者未正确注销
- 方案:使用弱引用或确保注销
private final Map<Observer, WeakReference<Observer>> observers = new ConcurrentHashMap<>();
问题2:通知顺序依赖
- 方案:引入优先级机制
observers.sort(Comparator.comparingInt(Observer::getPriority));
问题3:异常传播
- 方案:隔离处理每个观察者
observers.forEach(o -> { try { o.update(); } catch (Exception e) { log.error("Observer failed", e); } });
在电商系统订单模块的实践中,我们最终采用了Spring Event为主、自定义实现为辅的混合方案。核心状态变更使用同步的Spring Event保证事务一致性,非关键业务(如数据统计、日志记录)使用自定义的异步观察者实现。这种组合既保证了核心流程的可靠性,又提升了系统整体吞吐量。
更多推荐
所有评论(0)