引言:
在如今服务日益复杂的系统架构中,高可用与低耦合不再只是架构师的术语,而是每一位 Java 开发者必须掌握的工程能力。如何避免代码一改动就“牵一发动全身”?如何让系统在高并发场景下依然稳定?如何让我们的业务逻辑变得灵活、可插拔、可测试?
本篇文章将以真实业务场景驱动,从架构拆解到代码落地,手把手带你构建一套高内聚、低耦合、易扩展的业务中台系统,并引入事件驱动 + 观察者模式 + Spring 应用实践,让你在技术深度和广度上双重提升!
场景背景:订单系统的事件解耦设计
设想一个典型的订单系统,创建订单后需要执行如下操作:
- 写入数据库
- 发放优惠券
- 发送短信
- 写入审计日志
- 通知其他微服务
如果都放在 OrderService#createOrder()
里实现,那么代码会臃肿、不可测试且耦合严重,未来任何一个改动都可能牵动全局。
解耦目标
- 业务核心职责单一
- 各模块解耦,不互相依赖
- 支持后续扩展(如增加“积分发放”逻辑)
- 保持事务完整性或通过异步保证最终一致性
技术选型:
技术 | 用途 |
---|---|
Spring Boot | 基础框架 |
ApplicationEvent + Listener | 实现解耦 |
异步线程池 | 提升性能,支持异步事件 |
Redis、消息队列(可选) | 支持跨服务事件通知 |
核心代码实现
1️⃣ 定义订单创建事件
// 事件对象
public class OrderCreatedEvent extends ApplicationEvent {
private final Long orderId;
private final String userId;
public OrderCreatedEvent(Object source, Long orderId, String userId) {
super(source);
this.orderId = orderId;
this.userId = userId;
}
public Long getOrderId() {
return orderId;
}
public String getUserId() {
return userId;
}
}
2️⃣ 发布事件(在订单创建成功后)
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher publisher;
public void createOrder(OrderRequest request) {
// 1. 创建订单逻辑
Long orderId = saveOrderToDatabase(request);
// 2. 发布订单创建事件(同步/异步皆可)
publisher.publishEvent(new OrderCreatedEvent(this, orderId, request.getUserId()));
log.info("订单创建完成,已发布事件:orderId={}", orderId);
}
private Long saveOrderToDatabase(OrderRequest request) {
// 模拟数据库保存
return System.currentTimeMillis();
}
}
3️⃣添加监听器进行业务处理(发送短信、发放优惠券等)
@Slf4j
@Component
public class SmsNotificationListener {
// Spring 默认是同步调用,可以加 @Async 实现异步
@Async
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("接收到订单事件,准备发送短信通知:orderId={}, userId={}",
event.getOrderId(), event.getUserId());
// 模拟短信发送逻辑
// ...
}
}
@Slf4j
@Component
public class CouponGrantListener {
@Async
@EventListener
public void handleCouponGrant(OrderCreatedEvent event) {
log.info("准备为用户发放优惠券:userId={}", event.getUserId());
// 模拟发券逻辑
// ...
}
}
✅注意事项:开启异步支持
@Configuration
@EnableAsync
public class AsyncConfig {
// 自定义线程池(可选)
}
延伸:进一步解耦可使用 MQ(Kafka/RabbitMQ)
对于跨服务通知,比如通知库存服务,可以封装一个 Producer 将事件推送到消息队列中:
@Component
@RequiredArgsConstructor
public class OrderEventProducer {
private final RabbitTemplate rabbitTemplate;
public void sendOrderCreatedEvent(OrderCreatedEvent event) {
rabbitTemplate.convertAndSend("order.exchange", "order.created", event);
}
}
✅ 总结:
通过 ApplicationEvent + Listener
的设计方式,我们将核心业务与扩展逻辑彻底解耦,达成如下目标:
- 高可用:失败不影响主流程
- 低耦合:新增逻辑只需增加 Listener,无需改动核心代码
- 高扩展性:可随时替换异步处理方式(如换成 MQ)
- 高内聚:每个类职责单一,便于单测和维护
📌 推荐实践建议:
- 业务中台、订单中心、会员系统等场景中强烈建议使用事件驱动方式处理拓展性强的后置逻辑
- 异步逻辑如涉及事务一致性建议配合 MQ 或事件补偿机制(如本地消息表)
- 监听器建议精细化粒度控制,避免处理复杂流程
- 通过 Spring 的
@Order
注解控制监听器优先级(如需先发券再通知)