一、观察者模式概述
观察者模式(Observer Pattern)是一种行为型设计模式:
核心思想:
- 定义对象间一对多的依赖关系
- 当一个对象状态变化时,所有依赖它的对象都会收到通知
- 实现松耦合,被观察者和观察者可以独立变化
解决的问题:
- 分布式系统中的事件通知
- 服务间的异步通信
- 状态同步问题
- 业务解耦
二、模式结构
1. 基本结构
┌─────────────────────────────────────────────────────────────────┐
│ 观察者模式 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 观察者接口 │◀────────────────│ Subject接口 │ │
│ │ (Observer) │ register │ (Subject) │ │
│ └──────────────────┘ remove └────────┬─────────┘ │
│ △ notify │ │
│ │ │ │
│ │ ┌──────────────────┐ │ │
│ └────────│ 具体观察者1 │ │ │
│ │ ConcreteObserver │────────┘ │
│ └──────────────────┘ │
│ │
│ ┌──────────────────┐ │
│ │ 具体观察者2 │ │
│ │ ConcreteObserver │ │
│ └──────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2. Java实现
java
// 观察者接口
public interface Observer<T> {
void update(T event);
}
// 被观察者接口
public interface Subject<T> {
void attach(Observer<T> observer);
void detach(Observer<T> observer);
void notify(T event);
}
// 具体被观察者
public class Observable<T> implements Subject<T> {
private final List<Observer<T>> observers = new CopyOnWriteArrayList<>();
@Override
public void attach(Observer<T> observer) {
observers.add(observer);
}
@Override
public void detach(Observer<T> observer) {
observers.remove(observer);
}
@Override
public void notify(T event) {
observers.forEach(observer -> {
try {
observer.update(event);
} catch (Exception e) {
// 观察者执行异常不影响其他观察者
log.error("观察者执行异常", e);
}
});
}
}
三、分布式观察者模式
1. 事件总线架构
┌─────────────────────────────────────────────────────────────────┐
│ 分布式事件总线 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 服务A │───▶│ 消息 │───▶│ 消息总线 │───▶│ 服务B │ │
│ │(发布者)│ │ 队列 │ │(Kafka) │ │(订阅者) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ▲ │
│ ┌─────────┐ ┌─────────┐ │ │
│ │ 服务C │───▶│ 消息 │─────────────────┘ │
│ │(发布者)│ │ 队列 │ │
│ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2. Spring事件机制
java
// 定义领域事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
private final String eventId;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
this.eventId = UUID.randomUUID().toString();
}
public Order getOrder() {
return order;
}
public String getEventId() {
return eventId;
}
}
// 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher eventPublisher;
public Order createOrder(OrderRequest request) {
Order order = orderRepository.save(createOrder(request));
// 发布事件
eventPublisher.publishEvent(new OrderCreatedEvent(this, order));
return order;
}
}
// 监听事件
@Component
public class OrderEventListener {
@Autowired
private NotificationService notificationService;
@Autowired
private InventoryService inventoryService;
// 订单创建后发送通知
@EventListener
@Async
public void handleOrderCreated(OrderCreatedEvent event) {
Order order = event.getOrder();
notificationService.sendOrderCreatedNotification(order.getCustomerId());
}
// 订单创建后扣减库存
@EventListener
@Order(1)
public void handleOrderCreatedForInventory(OrderCreatedEvent event) {
Order order = event.getOrder();
for (OrderItem item : order.getItems()) {
inventoryService.deductStock(item.getProductId(), item.getQuantity());
}
}
}
3. 条件监听
java
// 条件监听
@Component
public class OrderStatusListener {
// 只监听已支付状态
@EventListener(condition = "#event.status == 'PAID'")
public void handlePaidOrder(OrderStatusChangedEvent event) {
// 触发后续流程
triggerShippingProcess(event.getOrderId());
}
// 只监听VIP客户
@EventListener(condition = "#event.customer.vip == true")
public void handleVipOrder(OrderCreatedEvent event) {
// VIP客户特殊处理
sendVipGift(event.getOrder());
}
}
四、消息队列实现
1. Kafka事件总线
java
// Kafka事件发布
@Service
public class KafkaEventPublisher {
@Autowired
private KafkaTemplate<String, Object> kafkaTemplate;
public void publish(String topic, DomainEvent event) {
kafkaTemplate.send(topic, event.getEventId(), event)
.whenComplete((result, ex) -> {
if (ex != null) {
log.error("事件发布失败: topic={}, eventId={}", topic, event.getEventId(), ex);
} else {
log.info("事件发布成功: topic={}, eventId={}, partition={}",
topic, event.getEventId(), result.getRecordMetadata().partition());
}
});
}
}
// Kafka事件订阅
@Component
public class OrderKafkaListener {
@KafkaListener(topics = "order-events", groupId = "order-service")
public void handleOrderEvent(ConsumerRecord<String, OrderEvent> record) {
OrderEvent event = record.value();
log.info("收到订单事件: eventId={}, type={}", event.getEventId(), event.getType());
switch (event) {
case OrderCreatedEvent created -> handleOrderCreated(created);
case OrderPaidEvent paid -> handleOrderPaid(paid);
case OrderCancelledEvent cancelled -> handleOrderCancelled(cancelled);
}
}
}
2. RocketMQ事件
java
// RocketMQ事务事件
@Service
public class RocketMQTransactionPublisher {
@Autowired
private TransactionMQProducer producer;
public void publishOrderEvent(Order order) {
Message message = new Message("order-topic", JSON.toJSONString(order).getBytes());
producer.sendMessageInTransaction(message, (msg, arg) -> {
// 执行本地事务
orderRepository.save((Order) arg);
return LocalTransactionState.COMMIT_MESSAGE;
}, order);
}
}
// RocketMQ监听
@Component
public class OrderTransactionListener implements TransactionListener {
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
Order order = JSON.parseObject(new String(msg.getBody()), Order.class);
orderRepository.save(order);
return LocalTransactionState.COMMIT_MESSAGE;
} catch (Exception e) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
return LocalTransactionState.COMMIT_MESSAGE;
}
}
五、观察者模式变体
1. 异步观察者
java
// 异步观察者实现
public class AsyncObserver<T> implements Observer<T> {
private final ExecutorService executor;
private final Observer<T> delegate;
public AsyncObserver(Observer<T> delegate, ExecutorService executor) {
this.delegate = delegate;
this.executor = executor;
}
@Override
public void update(T event) {
executor.submit(() -> {
try {
delegate.update(event);
} catch (Exception e) {
log.error("异步观察者执行异常", e);
}
});
}
}
// 异步事件发布
@Service
public class AsyncEventPublisher {
private final ExecutorService executor = Executors.newCachedThreadPool();
public <T> void publishAsync(DomainEvent event) {
CompletableFuture.runAsync(() -> publish(event), executor);
}
}
2. 优先级观察者
java
// 优先级观察者
public class PriorityObserver<T> implements Observer<T>, Comparable<PriorityObserver<T>> {
private final int priority;
private final Observer<T> observer;
public PriorityObserver(Observer<T> observer, int priority) {
this.observer = observer;
this.priority = priority;
}
@Override
public void update(T event) {
observer.update(event);
}
@Override
public int compareTo(PriorityObserver<T> o) {
return Integer.compare(o.priority, this.priority); // 优先级高的先执行
}
}
// 带优先级的被观察者
public class PriorityObservable<T> implements Subject<T> {
private final List<PriorityObserver<T>> observers = new ArrayList<>();
@Override
public void attach(Observer<T> observer) {
attach(observer, 0);
}
public void attach(Observer<T> observer, int priority) {
observers.add(new PriorityObserver<>(observer, priority));
observers.sort(null);
}
@Override
public void notify(T event) {
observers.forEach(o -> o.update(event));
}
}
3. 可撤销观察者
java
// 可撤销观察者
public class ObservableWithTimeout<T> implements Subject<T> {
private final List<Observer<T>> observers = new CopyOnWriteArrayList<>();
private final Map<Observer<T>, Long> attachTimes = new ConcurrentHashMap<>();
private final long timeoutMs;
public ObservableWithTimeout(long timeoutMs) {
this.timeoutMs = timeoutMs;
}
@Override
public void attach(Observer<T> observer) {
observers.add(observer);
attachTimes.put(observer, System.currentTimeMillis());
// 注册超时清理
scheduleCleanup(observer);
}
private void scheduleCleanup(Observer<T> observer) {
CompletableFuture.delayedExecutor(timeoutMs, TimeUnit.MILLISECONDS)
.execute(() -> {
Long attachTime = attachTimes.get(observer);
if (attachTime != null &&
System.currentTimeMillis() - attachTime > timeoutMs) {
detach(observer);
log.warn("观察者超时自动移除");
}
});
}
}
六、实战案例
1. 订单状态变更通知
java
// 订单被观察者
@Service
public class OrderSubject {
private final List<OrderObserver> observers = new CopyOnWriteArrayList<>();
public void attach(OrderObserver observer) {
observers.add(observer);
}
public void detach(OrderObserver observer) {
observers.remove(observer);
}
public void notifyObservers(Order order, OrderEvent event) {
observers.forEach(observer -> {
try {
observer.onOrderEvent(order, event);
} catch (Exception e) {
log.error("通知观察者失败", e);
}
});
}
}
// 订单观察者接口
public interface OrderObserver {
void onOrderEvent(Order order, OrderEvent event);
}
// 库存观察者
@Component
public class InventoryOrderObserver implements OrderObserver {
@Override
public void onOrderEvent(Order order, OrderEvent event) {
switch (event) {
case OrderEvent.CREATED -> handleOrderCreated(order);
case OrderEvent.PAID -> handleOrderPaid(order);
case OrderEvent.CANCELLED -> handleOrderCancelled(order);
}
}
private void handleOrderCreated(Order order) {
// 预占库存
inventoryService.reserveStock(order.getItems());
}
}
// 通知观察者
@Component
public class NotificationOrderObserver implements OrderObserver {
@Autowired
private NotificationService notificationService;
@Override
public void onOrderEvent(Order order, OrderEvent event) {
switch (event) {
case OrderEvent.CREATED -> {
notificationService.notifyCustomer("订单已创建: " + order.getOrderNo());
}
case OrderEvent.PAID -> {
notificationService.notifyCustomer("订单已支付: " + order.getOrderNo());
}
case OrderEvent.SHIPPED -> {
notificationService.notifyCustomer("订单已发货: " + order.getOrderNo());
}
}
}
}
2. 配置变更监听
java
// 配置变更监听
@Component
public class ConfigObserver {
private final Map<String, Consumer<String>> listeners = new ConcurrentHashMap<>();
public void register(String key, Consumer<String> listener) {
listeners.put(key, listener);
}
public void notifyChange(String key, String newValue) {
Consumer<String> listener = listeners.get(key);
if (listener != null) {
listener.accept(newValue);
}
}
}
// 使用示例
@Configuration
public class CacheConfig {
@Autowired
private ConfigObserver configObserver;
@PostConstruct
public void init() {
configObserver.register("cache.ttl", newValue -> {
// 动态更新缓存TTL
updateCacheTTL(Integer.parseInt(newValue));
});
}
}
七、分布式注意事项
1. 事件幂等
java
// 幂等处理
@Component
public class IdempotentEventHandler {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean isProcessed(String eventId) {
return Boolean.TRUE.equals(redisTemplate.hasKey("processed:" + eventId));
}
public void markProcessed(String eventId) {
redisTemplate.opsForValue().set("processed:" + eventId, "1", 24, TimeUnit.HOURS);
}
}
// 事件监听器
@Service
public class OrderEventService {
@Autowired
private IdempotentEventHandler idempotentHandler;
@KafkaListener(topics = "order-events")
public void handleOrderEvent(OrderEvent event) {
// 幂等检查
if (idempotentHandler.isProcessed(event.getEventId())) {
return;
}
try {
processEvent(event);
idempotentHandler.markProcessed(event.getEventId());
} catch (Exception e) {
log.error("处理事件失败", e);
}
}
}
2. 事件顺序
java
// 保证顺序处理
@Service
public class OrderedEventProcessor {
private final Map<String, AtomicInteger> processedVersions = new ConcurrentHashMap<>();
public void process(OrderEvent event) {
String key = event.getAggregateId();
AtomicInteger expectedVersion = processedVersions.computeIfAbsent(
key, k -> new AtomicInteger(0));
synchronized (expectedVersion) {
if (event.getVersion() != expectedVersion.get() + 1) {
// 事件顺序不对,等待重试
throw new OutOfOrderException("期望版本" + (expectedVersion.get() + 1)
+ ",实际版本" + event.getVersion());
}
doProcess(event);
expectedVersion.incrementAndGet();
}
}
}
3. 事件丢失处理
java
// 定时对账
@Component
public class EventReconciliation {
@Scheduled(fixedDelay = 60000)
public void reconcile() {
// 检查事件处理情况
List<String> pendingEventIds = eventStore.findPendingEvents();
for (String eventId : pendingEventIds) {
DomainEvent event = eventStore.findById(eventId);
if (event != null && isTimeout(event)) {
// 超时事件重新处理
reprocessEvent(event);
}
}
}
}
八、总结
观察者模式在分布式系统中的价值:
- 松耦合:发布者和订阅者解耦
- 异步通信:非阻塞事件通知
- 可扩展:方便添加新的观察者
- 分布式支持:通过消息队列实现
最佳实践:
- 做好事件幂等处理
- 注意事件顺序问题
- 实现超时重试机制
- 监控事件处理情况
个人观点,仅供参考