当前位置: 首页 > news >正文

【Spring Boot Starter 设计思考:分离模式是否适用于所有场景】

Spring Boot Starter 设计思考:分离模式是否适用于所有场景?

在 Spring Boot 生态中,starter + autoconfigure 的分离设计已成为广泛采用的标准模式。但当我们深入分析其在实际项目中的应用时,或许可以思考一下:这种设计是否真的是恰当的?

一、当前模式的分析

1. 官方及绝大多数流行框架的模式

当前大多数 Starter 采用这样的结构,其中 Starter 本身是一个空的聚合包,不包含任何实际代码:

<!-- mybatis-spring-boot-starter (空壳聚合包) -->
<dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></dependency>
</dependencies>

同时在 autoconfigure 模块中需要重新声明依赖:

<!-- mybatis-spring-boot-autoconfigure -->
<dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><optional>true</optional></dependency>
</dependencies>

这种设计带来的现象:

  • Starter 模块作为纯粹的依赖聚合空壳,不包含任何业务逻辑
  • 实际的自动配置逻辑位于独立的 autoconfigure 模块
  • 相同的依赖需要在两个位置声明,造成配置冗余

2. 自动配置类独立存在的思考

以 Redis 自动配置为例:

// org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

考虑这样的使用场景:

<!-- 用户只引入了基础库,未使用完整 starter -->
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId>
</dependency>

可能出现的情况:

  • 自动配置类检测到基础类存在,开始配置流程
  • 但由于缺少某些必要组件,配置可能无法完全生效
  • 这种"部分配置"的状态可能带来不确定性

二、自动配置类的本质思考

1. 自动配置类与 Starter 的天然联系

从功能角度看,自动配置类与 Starter 之间存在着紧密的关联:

  • 自动配置类的目的是让 Starter 能够开箱即用
  • Starter 的价值很大程度上通过自动配置类来体现
  • 两者在逻辑上是一个完整的功能单元

2. 关于 Condition 注解的思考

在当前的分离模式下,条件注解看起来是必要的:

@ConditionalOnClass({RedisTemplate.class, JedisConnection.class})

但如果我们换一个角度思考:当自动配置类位于 Starter 内部时,这些条件检查是否还有必要?

如果自动配置类直接放在 Starter 包内:

@Configuration
public class RedisAutoConfiguration {// 由于 Starter 已经包含了所有必要依赖,// @ConditionalOnClass 可能变得冗余
}

个人看法:
用户引入 Starter 的行为本身就表明了使用意图,Starter 的依赖管理已经确保了所需类的存在。在这种情况下,过多的 @ConditionalOnClass 检查反而可能增加了不必要的复杂性。

三、社区现状的分析

1. 广泛采用的模式

MyBatis、MyBatis-Plus、PageHelper 等流行项目都采用了与 Spring 官方相似的结构:

<!-- mybatis-spring-boot-starter -->
<dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></dependency>
</dependencies>

这种一致性主要基于:

  • 学习成本考虑:开发者已经熟悉这种组织结构
  • 生态一致性:保持与其他组件的统一结构
  • 风险规避:遵循经过验证的实践方案

2. Spring 官方的特殊考量

Spring 团队采用集中式的 autoconfigure 设计,可能基于以下考虑:

  • 统一管理:协调大量第三方库的适配
  • 版本控制:统一管理配置类的兼容性
  • 框架生态:维护整个 Spring Boot 生态的一致性

但这种针对框架级别的设计考量,并不一定适用于所有的自研 Starter 场景。

四、自研 Starter 的替代方案思考

1. 内聚式设计

对于自研的 Starter,可以考虑采用更加内聚的设计:

company-spring-boot-starter/
├── src/main/java
│   └── com/company/autoconfigure/
│       ├── CompanyAutoConfiguration.java
│       └── CompanyProperties.java
├── src/main/resources
│   └── META-INF
│       ├── spring.factories
│       └── spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── pom.xml

2. 简化的依赖管理

只需要在 Starter 中声明一次依赖:

<dependencies><dependency><groupId>com.company</groupId><artifactId>company-core</artifactId></dependency><!-- 其他运行时依赖 -->
</dependencies>

这样可以避免:

  • 独立的 autoconfigure 模块创建和维护
  • 重复的依赖声明
  • optional 依赖的复杂管理

3. 合理的条件注解使用

在内聚式设计中,可以更加有选择地使用条件注解:

@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class CompanyAutoConfiguration {@Bean@ConditionalOnMissingBean  // 保留:允许用户自定义public CompanyService companyService() {return new DefaultCompanyService();}@Bean@ConditionalOnProperty(prefix = "company", name = "feature.enabled")public FeatureService featureService() {return new FeatureService();}
}

个人建议:

  • 保留 @ConditionalOnMissingBean 尊重用户自定义
  • 保留 @ConditionalOnProperty 支持功能开关
  • 保留 @AutoConfigureAfter 确保配置顺序
  • 酌情减少 @ConditionalOnClass 的使用

五、对传统分离模式的重新审视

分离模式的实际价值有限

从实际应用角度来看,传统分离模式的优势场景相当有限:

  • Spring 官方场景:仅当需要统一管理几十个不同组件的配置和版本时,集中式的 autoconfigure 包才有其管理上的便利性
  • 第三方组件场景:对于大多数独立的第三方组件来说,这种分离带来的更多是复杂性而非价值

内聚式设计的普适优势

相比之下,内聚式设计在大多数场景下都表现出更好的特性:

  • 架构简洁:减少不必要的模块分层,降低系统复杂度
  • 维护便利:所有相关代码集中在同一模块,便于理解和修改
  • 依赖明确:避免重复的依赖声明,减少配置错误可能性
  • 意图清晰:Starter 作为一个完整的功能单元,职责单一明确

六、总结与建议

经过对 Spring Boot Starter 设计模式的深入分析,我认为传统的分离模式在大多数应用场景下可能并非最优选择。

核心观点:

  • 自动配置类本质上与其对应的 Starter 是高度内聚的,强行分离反而引入不必要的复杂性
  • 对于绝大多数项目(特别是自研 Starter),将自动配置类直接包含在 Starter 包内是更加简单直接的设计
  • 只有在类似 Spring 官方需要统一管理大量第三方组件配置的特殊场景下,集中式的 autoconfigure 设计才有其合理性

实践建议:
在开发自研 Starter 时,建议优先考虑内聚式设计。这种设计不仅减少了模块间的依赖关系,简化了构建配置,还使得代码结构更加直观易懂。只有当确实需要支持高度灵活的可选依赖组合时,才考虑采用传统的分离模式。

技术决策应当基于实际需求和具体场景,而非盲目遵循某种"标准做法"。在理解现有设计背后的考量的同时,保持批判性思维,选择最适合自己项目的技术方案,这才是技术人应有的态度。

http://www.dtcms.com/a/553334.html

相关文章:

  • HTTP 头部参数数据注入测试sqlilabs less 18
  • 网站速度慢的原因做网站建设优化的电话话术
  • 【数据结构】单链表 练习记录
  • mac 安装 jdk17
  • 【项目实战1-瑞吉外卖|day22】
  • 怎么用dw做响应式网站网站主持人制作网站代言人
  • Android开发自学笔记 --- Kotlin
  • 从VB到PyCharm:编程工具跨越时代的传承与革命
  • 网站建设创新成果四年级写一小段新闻
  • 生产环境用Go语言完成微服务搭建和业务融入
  • 第九课 四川料理は辛いです
  • DevEco Studio在模拟器中改变运行的 ets 文件
  • 第5讲:项目依赖管理与资源管理
  • 网站定制案例微安电力wordpress 分类合并
  • Orleans 的异步
  • comsol livelink with matlab
  • PDF文档中表格以及形状解析-后续处理(线段生成最小多边形)
  • 5G工业边缘计算网关,重构工业智能化
  • 网站中英文切换代码wordpress插件问题
  • 解析 Lua 虚拟机整数与浮解析 Lua 虚拟机整数与浮点数处理:类型转换与运算精度控制
  • 个人网站可以做充值工业设计网页
  • 【C/C++刷题集】二叉树算法题(一)
  • Java Stream 流式编程
  • 如何进入公司网站的后台怎样用vs做简单网站
  • 长春手机建站模板wordpress搜索页
  • 消除链上气泡图:为什么换仓正在成为新的链上生存策略?
  • 什么是TRS收益互换与场外个股期权:从金融逻辑到系统开发实践
  • ARM《8》_制作linux最小根文件系统
  • IntelliJ IDEA 如何全局配置 Maven?避免每次打开新项目重新配置 (适用于 2024~2025 版本)
  • vmware17安装ubuntu2204版本qemu运行armv8处理器uboot运行调试的一些工作