Skip to content

开发与重构计划 ​

DDK 的构建方式、模块划分、测试要求,以及当前的重构排期与已知缺陷清单。

一、环境与构建 ​

项要求
JDK21
Maven3.9+
Spring Boot4.1.1(根 pom 的 parent,Jackson 3)
CIJava 21 与 Java 25 两个版本
bash
# 全量构建 + 测试(CI 用的就是这条)
mvn -B -ntp verify

# 安装到本地仓库
mvn -B install

# 只构建某个模块及其依赖
mvn -B -pl ddk-starters/ddk-cache-starter -am install

不要用 -DskipTests。 它只跳过测试执行、不跳过测试编译。项目历史上正是因为习惯性加这个参数,一个测试类里的 Kotlin 式 import ... as ... 语法错误让整个 reactor 长期构建失败而无人发现——ddk-cache-starter 之后的 8 个模块全部 SKIPPED。真要跳过测试用 -Dmaven.test.skip=true,但那只应该用于临时排查。

CI 配置在 .github/workflows/build.yml,push 和 PR 都会跑 mvn verify。

二、模块划分 ​

domain-driven-kit
├── ddk-dependencies      BOM,下游 import 后无需再写版本号
├── ddk-core              核心抽象,不依赖持久层框架
├── ddk-mybatis           ddk-core 的 MyBatis-Plus 实现
├── ddk-starters          8 个 Spring Boot starter
│   ├── ddk-web-starter
│   ├── ddk-mybatis-starter
│   ├── ddk-redis-starter
│   ├── ddk-cache-starter
│   ├── ddk-db-starter
│   ├── ddk-tracer-starter
│   ├── ddk-seata-starter
│   └── ddk-archguard-starter
├── ddk-archetypes        三层 / 四层 Maven archetype
└── ddk-examples          可运行示例(ddk-example-user)

模块依赖约束:

  • ddk-core 不得依赖任何持久层框架。com.ddk.core.domain 包更严格,不得依赖任何框架
  • ddk-mybatis 依赖 ddk-core + MyBatis-Plus
  • starter 依赖 ddk-core,可以依赖 ddk-mybatis,不得互相依赖

三、写 starter 的规范 ​

新增或改造 starter 时按这套模式,八个 starter 目前风格不统一,正在逐步收敛:

1. 独立配置前缀 + @ConfigurationProperties

java
@ConfigurationProperties(prefix = "ddk.xxx")
public class DdkXxxProperties {
    private boolean enabled = true;
    // ...
}

不要复用 Spring Boot 自己的前缀(如 spring.cache.*)。ddk-cache-starter 复用了,结果和 Boot 的自动配置产生循环条件,上下文起不来。

2. 显式声明加载顺序

java
@AutoConfiguration(before = SomeBootAutoConfiguration.class, after = AnotherAutoConfiguration.class)

不要靠 @Primary 硬压 Boot 的自动配置——那只是掩盖顺序问题。

3. 依赖不可用时降级,不要启动失败

starter 提供的是增强能力,不该成为可用性单点。Redis 连不上就退化成本地缓存,追踪组件缺失就不注册,都比启动失败好。

4. 可选依赖用 ObjectProvider

java
// 错:@Bean 方法参数上的 @Autowired(required=false) 不生效,缺 Bean 会抛异常
public CacheManager cacheManager(@Autowired(required = false) CacheManager delegate) { }

// 对
public CacheManager cacheManager(ObjectProvider<CacheManager> provider) {
    CacheManager delegate = provider.getIfAvailable();
}

5. 注册 AutoConfiguration.imports

src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

不要用 Spring Boot 2 的 spring.factories。

6. 提供配置元数据

src/main/resources/META-INF/additional-spring-configuration-metadata.json

目前没有任何 starter 提供,IDE 里没有配置补全。根 pom 的 annotationProcessorPaths 已经加上 spring-boot-configuration-processor,缺的是元数据文件本身。

7. 库里不要携带全局配置文件

库 jar 里的 logback-spring.xml、application.yml 会随 classpath 生效,覆盖使用方的配置。ddk-web-starter 早期就携带过 logback-spring.xml,已经移除;日志、端口这类全局配置只能由应用自己决定。

四、测试要求 ​

模块类型要求现状
ddk-core纯单元测试,不启动容器有
ddk-mybatis单测 + H2 或 Testcontainers 集成测试单测 + H2 集成测试
starterApplicationContextRunner 测试装配条件 + 降级行为;依赖外部组件的用 Testcontainers全部有;cache 用 Testcontainers 启动 Redis
archetype集成测试生成项目并执行 mvn verify两个 archetype 都有,CI 通过 -Parchetype-it 开启
example通过 HTTP 走完整用例 + 架构测试ddk-example-user 有

com.ddk.core.domain 额外有一条:DomainPackagePurityTest 断言整个包只依赖 JDK 与自身。加任何第三方依赖都会让它失败——这是有意的,领域基类是要被下游继承的。

断言行为,不要断言 Bean 类型。

这条是从真实教训里来的。ddk-cache-starter 的测试断言 assertThat(manager).isInstanceOf(CompositeCacheManager.class),断言通过了,但它保护的是实现细节,完全没发现「Redis 层根本不会被访问」这个根本性缺陷。正确的断言是「往 Redis 直接写一个值,读取时能命中并回填到 L1」。

ApplicationContextRunner 有两个坑要知道:

  • 它不读取 classpath 上的 AutoConfiguration.imports,只处理显式传入 AutoConfigurations.of(...) 的类。要验证第三方 Bean,必须把对应的自动配置一并列出
  • 它不执行 spring.factories 里注册的 ApplicationContextInitializer。依赖这些初始化器的框架(如 Seata)无法在这种测试里验证,必须用 @SpringBootTest

五、当前缺陷清单 ​

按严重程度排列。P0 会导致功能不可用或运行时崩溃。

P0 ​

缺陷位置状态
ddk-cache-starter 用 CompositeCacheManager 实现多级缓存,Redis 层永不被访问ddk-cache-starter✅ 已按设计文档重写为 TwoLevelCache
archetype 不是可用的 Maven archetype(缺 archetype-metadata.xml 等)ddk-archetypes✅ 已改造,含生成项目的集成测试
ddk-examples 完全是空的ddk-examples✅ 已补 ddk-example-user
DefaultMapper 把数据映射成空 Object,仓储调用运行时抛 ClassCastExceptionddk-core mapper + ddk-mybatis✅ 已修,改为抛 MissingMapperException
MapperProvider 用 @Component,库 jar 里靠使用方 component scan 才能注册ddk-core✅ 已修,改由 ddk-mybatis-starter 自动配置注册
BaseExceptionHandler 缺 @RestControllerAdvice,全局异常处理不生效ddk-web-starter✅ 已修
整个 reactor 构建失败ddk-cache-starter 测试语法错误✅ 已修
MultiDataSourceAutoConfiguration 作为 BFPP 却有构造器注入,上下文起不来ddk-db-starter✅ 已修
无 CI仓库✅ 已加
Redis 序列化用 LaissezFaireSubTypeValidator 开启默认类型,写得进 Redis 就能让应用实例化任意类ddk-redis-starter✅ 已修,改为包白名单

P1 ​

缺陷位置状态
CORS 默认 allowedOriginPatterns("*") + allowCredentials(true) 全放开且不可配ddk-web-starter✅ 已修,默认关闭,ddk.web.cors.* 可配
库里携带 logback-spring.xml,会覆盖使用方的日志配置ddk-web-starter✅ 已删
web / redis 两个 starter 没有测试ddk-starters✅ 已补
AggregateRoot.version() 没有在 GenericRepositoryImpl 里打通乐观锁ddk-mybatis✅ 已打通,默认装 OptimisticLockerInnerInterceptor
DomainEventPublisher 的 Spring 实现还在 archetype 里,没有收进 starterddk-starters✅ 已收进 ddk-event-starter
三层 archetype 只有一个 Application 类ddk-archetypes✅ 已补齐,含三层架构规则
ddk-core 无领域模型基类ddk-core✅ 已实现,文档
MapperProvider 类型键用 SimpleName,跨包同名会静默覆盖ddk-core✅ 已修,改用全限定名
MapperProvider 在构造器里触发全量 Bean 实例化ddk-core✅ 已修,改为 SmartInitializingSingleton
ddk-dependencies 是空壳 BOMddk-dependencies✅ 已填充
ddk-core / ddk-mybatis 完全没有测试两个核心模块✅ 已补,79 个
mybatis-starter 没有测试ddk-starters✅ 已补

已修记录 ​

问题位置状态
PageQuery.addSort() 无效,排序被静默忽略ddk-mybatis✅ 已修
PageQuery.pageSize 无上限ddk-core✅ 已修
CommonArchRules 允许 Domain→Infrastructure,违反 DIPddk-archguard-starter✅ 已修
GenericRepository 泛型顺序 <ID, E> 与 javadoc 及社区习惯相反ddk-core✅ 已改为 <E, ID>

P2 ​

缺陷位置
无 checkstyle / spotless;jacoco 只出报告没有门槛根 pom
pom description 与实现不符(redis 宣称分布式锁/限流、mybatis 宣称数据权限,均未实现)两个 starter
自动配置类与框架同名(MybatisPlusAutoConfiguration),排错易混淆ddk-mybatis-starter
archunit-junit5-api 是 compile 作用域ddk-archguard-starter
Specification 不能下推到 SQL,复杂查询仍要走 Mapper XMLddk-core / ddk-mybatis

六、重构排期 ​

阶段 0 · 恢复构建(已完成) 修测试语法错误、修 db-starter 的 BFPP 问题、修 cache-starter 上下文启动、对齐 Seata 包名、补 tracer 依赖、加 CI。

阶段 1 · 工程基线(已完成) ✅ ddk-dependencies 填充成真 BOM;✅ CI;✅ 根 pom 补 spring-boot-configuration-processor; ✅ JaCoCo 按模块设门槛(行 ≥ 70%、分支 ≥ 50%);✅ Spotless 检查未使用 import 与空白字符(不做整体格式化,避免与 150 列单行风格冲突)。

阶段 2 · 领域模型与仓储(已完成) ✅ Identifier / ValueObject / Entity / AggregateRoot / DomainEvent / Specification; ✅ MapperProvider 找不到映射器直接失败、key 用全限定名、由自动配置注册; ✅ 通用仓储打通乐观锁与领域事件发布;✅ ddk-core 单测与 ddk-mybatis 的 H2 集成测试。

阶段 3 · starter 规范化(已完成) ✅ 全部 starter 统一 ddk.* 前缀并生成配置元数据;✅ 重写 ddk-cache-starter 为两级缓存;✅ Redis 反序列化白名单; ✅ CORS 默认关闭且可配、移除 logback-spring.xml;✅ CommonArchRules 用测试夹具验证能抓到违规。

阶段 4 · archetype 与示例(已完成) ✅ 三层 / 四层骨架改造成 Maven archetype,集成测试构建生成的项目;✅ ddk-examples/ddk-example-user 可运行示例。

阶段 5 · 发布就绪 稳定包名与公开契约、语义化版本策略、公开 API 的 Javadoc。

暂不发布到 Maven 中央仓库,因此 gpg 签名、distributionManagement、javadoc 插件等发布相关配置不在排期内。

七、提交约定 ​

  • 提交信息用 <type>: <描述>,type 取 feat / fix / refactor / docs / test / chore
  • 一次提交只做一件事。修构建和加特性不要混在一起
  • 改动 starter 行为时,同步更新 codesphere 文档站对应的 starter 文档
  • 不要提交 target/ 或 IDE 配置

相关文档 ​

文章以 CC BY-NC-SA 4.0 授权 · 代码片段以 MIT 授权