六边形架构中如何外部化适配器构件?多微服务审计场景问询
解决方案
核心思路:抽象通用契约 + 适配转换层
要解决这个问题,核心是把审计操作的通用行为契约从各个服务的具体实现中抽离出来,同时让适配器只依赖通用契约,不直接耦合服务的具体类。
1. 抽离通用审计端口与数据契约
创建一个独立的通用核心构件(比如audit-core),里面定义所有服务共用的审计接口和与数据库schema对齐的通用数据模型:
// 通用审计端口,放在audit-core构件中 package org.example.audit.port; public interface GenericAuditRepository { void save(GenericAuditRecord record); } // 通用审计数据模型,与数据库结构完全匹配 package org.example.audit.domain; public class GenericAuditRecord { // 定义数据库对应的字段:操作人ID、操作时间、服务标识、审计内容等 }
这个构件是所有服务和适配器的共同依赖,只包含通用契约,不涉及任何服务的具体代码。
2. 改造各服务端口,适配通用契约
每个服务的原有AuditRepository端口,改为继承通用端口,同时在服务内部实现自身AuditRecord到GenericAuditRecord的转换逻辑:
// 服务1的审计端口,继承通用端口 package org.example.service1.port; import org.example.audit.port.GenericAuditRepository; import org.example.service1.domain.AuditRecord; public interface AuditRepository extends GenericAuditRepository { // 保留服务专属的save方法,内部自动转换为通用模型 default void save(AuditRecord record) { GenericAuditRecord genericRecord = convertToGeneric(record); save(genericRecord); } // 服务内部实现转换逻辑 GenericAuditRecord convertToGeneric(AuditRecord record); }
这样每个服务的端口依然属于应用核心,同时复用了通用契约,避免重复定义。
3. 实现独立的数据库适配器构件
创建独立的audit-adapter-db构件,仅依赖audit-core,实现通用的GenericAuditRepository接口:
package org.example.audit.adapter.db; import org.example.audit.port.GenericAuditRepository; import org.example.audit.domain.GenericAuditRecord; // 引入数据库操作依赖(如JPA、MyBatis等) public class DbAuditRepositoryAdapter implements GenericAuditRepository { @Override public void save(GenericAuditRecord record) { // 直接基于通用模型执行数据库操作,与服务具体类完全解耦 // 示例:转换为JPA实体类并保存 } }
这个适配器不需要依赖任何服务的代码,只处理通用模型,可适配所有服务的审计需求。
4. 服务侧注入适配器并完成转换
每个服务通过DI框架(如Spring)将适配器实例注入到自身的审计端口,同时封装转换逻辑:
// 服务1的配置类 package org.example.service1.config; import org.example.service1.port.AuditRepository; import org.example.audit.adapter.db.DbAuditRepositoryAdapter; import org.springframework.context.annotation.Bean; public class AuditConfig { @Bean public AuditRepository auditRepository(DbAuditRepositoryAdapter genericAdapter) { return new AuditRepositoryImpl(genericAdapter); } // 服务内部实现类,封装转换逻辑 private static class AuditRepositoryImpl implements AuditRepository { private final GenericAuditRepository genericAdapter; public AuditRepositoryImpl(GenericAuditRepository genericAdapter) { this.genericAdapter = genericAdapter; } @Override public GenericAuditRecord convertToGeneric(AuditRecord record) { GenericAuditRecord generic = new GenericAuditRecord(); generic.setOperator(record.getOperatorId()); generic.setServiceId("service1"); // 完成其他字段的映射 return generic; } @Override public void save(GenericAuditRecord record) { genericAdapter.save(record); } } }
关键优势
- 消除重复:通用契约仅定义一次,所有服务复用,避免每个服务重复编写相同的端口和模型。
- 解耦适配器:适配器只依赖通用核心,不耦合任何服务的具体代码,保持独立构件的纯净性。
- 符合六边形架构:端口依然属于每个服务的应用核心,适配器作为外部依赖注入,架构边界清晰。
内容的提问来源于stack exchange,提问作者Mr.Bere
相关产品推荐
相关产品推荐

