领域战略建模:解密共享内核(Shared Kernel)的版本管理规范
在开展中大型微服务架构设计时,限界上下文(Bounded Context)的彻底解耦是核心诉求。然而,在实际工程中,团队之间往往会面临一些公共领域概念的强交叉(例如:“订单上下文”与“配送上下文”都需要使用完全一致的「地理围栏(Geo-Fence)」算法与数据模型;或者全网所有服务都需要复用同一套「用户基本身份结构」)。
如果为了追求绝对的解耦,让每个团队在各自上下文里重复开发、各自存储,会导致数据冗余错乱、维护成本翻倍;而构建繁重的防腐层(ACL)又显得大材小用。为了优雅处理这种“强共性、不可分割”的领域模型,领域驱动设计(DDD)推荐使用**共享内核(Shared Kernel)**集成模式。
本文将系统拆解共享内核的依赖划分原则、共享内核与防腐层的技术权衡、以及如何规范地进行多团队共享内核的版本发布协同。
一、 核心对比:防腐层 (ACL) vs. 共享内核 (Shared Kernel)
不同集成模式在团队沟通频次、代码独立性与共享深度上存在根本差异:
| 特征维度 | 防腐层 (Anti-Corruption Layer) | 共享内核 (Shared Kernel) |
|---|---|---|
| 代码重合度 | **零重合**。双端限界模型独立编译,在运行期通过数据翻译层沟通。 | **部分重合**。双端物理共享同一份核心代码包(如 Jar、SDK)或共享数据库表。 |
| 变更决定权 | 本域团队拥有 100% 决定权。外部变动不会直接影响本域编译。 | **双端共同决定**。任何一方无权擅自修改共享内核,必须开会达成共识。 |
| 沟通频次要求 | 低。按约定的公开 API 协议交互即可。 | **极高**。需要建立联合版本审查委员会,管理共享代码升级。 |
| 典型适用边界 | 两个限界上下文业务差异极大、处于不同核心级的调用。 | 两个限界上下文业务高度紧密、且共享模型改动极其罕见的场景。 |
二、 共享内核版本演进与多团队协作拓扑
在共享内核模式下,多团队通过共同开发一个只读的共享 SDK 包,并在各自限界上下文里实现硬集成的流转拓扑如下:
[ 核心领域: 地理围栏 (Geo-Fence Domain Model) ]
│
▼ 1. 抽取并发布到内部 Maven 仓库
【 共享内核 Jar 包: geo-kernel-1.0.0.jar 】
│
┌────────────────┴────────────────┐
▼ 2a. 团队 A 导入依赖 ▼ 2b. 团队 B 导入依赖
[ 配送上下文 (Delivery Context) ] [ 调度上下文 (Schedule Context) ]
│ │
▼ 3a. 本地业务方法强复用 ▼ 3b. 本地业务方法强复用
(直接调用 GeoPoint 等值对象) (直接调用 GeoPoint 等值对象)
│
▼ 4. 团队 A 提出算法升级需求 (v1.0.0 ──> v2.0.0)
【 共享内核版本决策会议 (双端团队参与) 】
│
┌─────────────┴─────────────┐
(通过) (否决)
▼ ▼
[ 5. 发布 geo-kernel-2.0.0.jar ] [ 保持 1.0.0 版本 ]
[ 团队 B 在约定排期内被动升级 ]
---三、 代码实战:在 Java 中落地共享内核依赖规范
以下代码展示了如何在一个独立的 Maven Module(共享内核)中,封装两个团队都需要使用的“地理围栏(Geo-Fence)”值对象,供下游限界上下文直接使用:
1. 共享内核层:定义只读、高内聚的值对象(Shared Kernel Layer)
package com.company.shared.kernel.geo;
import java.io.Serializable;
import java.util.Objects;
/**
* 共享内核值对象:地理坐标点
* 规约:共享内核代码必须保持高度稳定,不可包含任何非通用的技术噪音,属性全部只读(Immutable)
*/
public final class GeoPoint implements Serializable {
private final double longitude;
private final double latitude;
public GeoPoint(double longitude, double latitude) {
if (longitude < -180 || longitude > 180) {
throw new IllegalArgumentException("经度超出物理范围!");
}
if (latitude < -90 || latitude > 90) {
throw new IllegalArgumentException("纬度超出物理范围!");
}
this.longitude = longitude;
this.latitude = latitude;
}
public double getLongitude() { return longitude; }
public double getLatitude() { return latitude; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GeoPoint geoPoint = (GeoPoint) o;
return Double.compare(geoPoint.longitude, longitude) == 0 &&
Double.compare(geoPoint.latitude, latitude) == 0;
}
@Override
public int hashCode() {
return Objects.hash(longitude, latitude);
}
}
2. 限界上下文 A:直接引入共享内核进行配送派单(Downstream Context A)
package com.company.sales.delivery.domain.model;
import com.company.shared.kernel.geo.GeoPoint; // 直接依赖共享内核
/**
* 配送单聚合根(限界上下文 A)
*/
public class DeliverySheet {
private final String sheetId;
private GeoPoint destination; // 引入共享内核值对象
public DeliverySheet(String sheetId, GeoPoint destination) {
this.sheetId = sheetId;
this.destination = Objects.requireNonNull(destination);
}
public void updateDestination(GeoPoint newDest) {
this.destination = Objects.requireNonNull(newDest);
}
public GeoPoint getDestination() { return destination; }
}
---四、 总结
共享内核(Shared Kernel)是削减多系统重复开发、在紧密限界上下文间达成物理级统一的“强力粘合剂”。
It 通过**将共性领域实体与高精尖业务算法抽取为独立的只读依赖包,杜绝了多团队间的重复建设与数据表达不一的死穴;并利用双边共商的决策机制,强制保证了共享资产在演进过程中的稳定性**。掌握这套共享内核的适用规约、多团队变更对齐流程与 Maven 依赖隔离设计,是进行微服务集群公共依赖重构、掌控大团队协同架构设计 of 核心看家本领!
本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。



暂无评论
还没有人评论过本文,快来发表你的高见吧!