大迭代(二):事件聚合异构更新 —— 责任链重构
需求背景
大迭代的第三个方向:重构 ES 异构流程。
随着接入的数据源越来越多,ES 异构代码变成了一个"大杂烩":基础字段的异构逻辑、EAV 属性的异构逻辑、库存系统的异构逻辑、点评系统的异构逻辑……全部混在一起。每次接入新系统,都要在这堆代码里找位置、加逻辑,改完还要担心影响其他部分。
问题现状
当前的异构流程大概是这样的:
任意数据变更
↓
进入异构方法
↓
if (基础字段变更) { 处理基础字段 }
if (EAV属性变更) { 处理EAV属性 }
if (库存变更) { 调用库存接口,处理库存字段 }
if (点评变更) { 调用点评接口,处理点评字段 }
...
↓
拼装 ES 文档
↓
更新 ES
问题很明显:所有逻辑耦合在一起,新增一个数据源就要改这个方法,改一处可能影响全局,测试成本很高。
核心矛盾
ES 异构的本质是:收集一个实体的所有相关数据,拼装成 ES 文档,写入 ES。
这个过程天然是可以拆分的:不同来源的数据,由不同的模块负责收集,最后统一拼装。问题在于当前没有这层抽象,所有逻辑都堆在一起。
方案设计
抽象统一流程
把 ES 异构的整个过程抽象成四个环节:
实体变更事件
→ 聚合变更信息(责任链)
→ 构造 ES 文档
→ 更新 ES(含异常处理)
任何数据变更,无论来自基础字段、EAV 属性还是外部系统,都抽象成一个"变更事件",进入同一套流程处理。
责任链模式
聚合环节采用责任链模式,每个 Handler 负责一类数据的收集:
变更事件
↓
责任链
├→ BasicFieldHandler (基础字段)
├→ EAVAttributeHandler (EAV 扩展属性)
├→ StockInfoHandler (库存信息)
├→ ReviewInfoHandler (点评信息)
└→ [可扩展] 新系统 Handler
↓
聚合实体(BookInfoSearchEntity)
↓
ES 文档构造器
↓
ES 更新器(含重试和幂等)
每个 Handler 只负责自己那部分数据,互不干扰。新增一个数据源,只需要新增一个 Handler,现有代码完全不需要改动——这正是开闭原则的体现。
Handler 接口设计
public interface ESDocumentHandler {
// 填充 ES 文档的对应部分
void fillDocument(EntityChangeEvent event, BookESDocument document);
}
以点评信息为例:
@Component
public class ReviewInfoHandler implements ESDocumentHandler {
@Override
public void fillDocument(EntityChangeEvent event, BookESDocument document) {
ReviewInfo review = reviewRpcService.getReviewInfo(bookId);
document.setStarLevel(review.getStarLevel());
document.setCommentCount(review.getCommentCount());
document.setGoodCommentCount(review.getGoodCommentCount());
}
}
统一的事件处理器
@Service
public class ESDocumentSyncService {
@Autowired
private List<ESDocumentHandler> handlers; // Spring 自动注入所有 Handler
public void syncDocument(EntityChangeEvent event) {
BookESDocument document = new BookESDocument();
document.initEmptyDoc(event.getBookId())
// 责任链:每个 Handler 填充自己负责的部分
handlers.stream()
.forEach(h -> h.fillDocument(event, document));
// 统一更新 ES(含重试和幂等)
esRepository.upsert(document);
}
}
成本对比
优化前(接入观看人数系统):修改异构方法,集成新系统数据,变更多,测试麻烦,耗时 2-3 天。
优化后:新增 ViewCountHandler,实现方法,单元测试,耗时 1 天。
| 维度 | 优化前 | 优化后 |
|---|---|---|
| 接入新系统周期 | 2-3 天 | 1 天 |
| 影响范围 | 异构代码整体 | 独立 Handler |
| 测试成本 | 全面回归 | 单元测试 |
| 代码可读性 | 混乱 | 职责清晰 |
这一步解决了什么
ES 异构流程终于有了清晰的结构。每个数据源对应一个独立的 Handler,职责单一,互不影响。新增数据源只需新增 Handler,不会触碰任何现有代码。
大迭代的前三个方向都完成了。最后一个,也是最核心的问题:标签嵌套规则的配置化。