我们要定义一个生产可用的 Starter ,还有几个细节,我们必须要关注。这些细节可以很好的帮助我们写出更优秀的 Starter
一、maven 包依赖
每一个 Starter,可以理解为一个 Jar,这个 Jar 包,如果被其他应用引用,将会引发很多问题,
比如 Jar 包冲突。我们可以参考一些工具包是如何管理他们的 maven 的。
1.1 maven 之 optional
下面是 hutool 包中 maven
那么 optional 的作用是什么呢?
在 Maven 项目中,<optional>true</optional>
标记用于依赖声明中,表明这个依赖对当前项目是可选的,而不是必需的。这意味着,当其他项目引用声明了这个可选依赖的项目时,这个可选依赖不会自动被包含进那些项目的依赖树中。
具体来说,这个标记的主要作用包括:
避免依赖传递:当项目A包含一个标记为<optional>true</optional>的依赖B时,如果有另一个项目C依赖于项目A,那么B不会被自动包含为C的依赖。避免依赖传递带来的潜在问题,例如版本冲突或不必要的依赖膨胀。
模块化设计:通过将某些功能依赖标记为可选,你可以设计出更加模块化的项目。这样,用户可以根据需要选择是否引入这些功能,这对于创建具有插件或可扩展特性的库和框架尤其有用。
因此,我们在设计 Starter 依赖的时候,对于一些依赖包,我们也可以选择使用 <optional>true</optional>
。减少因为引入我们的 Starter 而代理的依赖传递。
例子:我们选择将 spring-boot-starter 标签设置 optional 为 true。
一旦 Starter 发布为 Jar ,那么版本就固定了。所以设置 optional 为 true,是一种好习惯。
1.2 maven 之 scope
我们有时候,希望引入的依赖,由容器提供。打包程序的时候不再引入,这个时候我们可以考虑设置 scope 的属性。
在编译和测试时,项目需要这个依赖,但是在运行时环境中,这个依赖已经存在,不需要打包进来。这一点是十分重要的。
在打包阶段,Maven 不会将 scope 为 "provided" 的依赖项包含进最终构建的 JAR、WAR 或 EAR 文件中。
举例:如果某个项目 A 依赖于项目 B,并且项目 B 中有一个 "provided" scope 的依赖 C,那么依赖 C 不会传递给项目 A。项目 A 必须显式声明对 C 的依赖才能使用它,除非也是将其声明为 "provided"
因此,我们在设计一个 Starter 的时候,是非常有必要关注这两个属性的。不要因为引入我们的 Starter,而给使用方带来更多的问题。
- 减少包大小:如果你的应用将要部署到提供了某些库的环境中,那么没有必要将这些库打包到你的应用中。通过将这些依赖的 scope 设置为 ,可以减小最终的包大小,加快部署速度并减少资源占用。
- 避免版本冲突:如果运行时环境已经提供了某个库的某个版本,而应用也包含了这个库的另一个版本,这可能会导致版本冲突。通过使用 scope,可以确保应用使用的是环境中已经存在的那个版本,从而避免冲突。
大多数 jar 是被 springBoot 引用使用, 这个时候,如果有中间件的情况,可以考虑将 Starter 中的一些中间件设置成 provided。从而避免重复地引入
虽然使用 scope 有其好处,但也需要注意确保运行时环境确实提供了这些依赖。如果你错误地将某个必需的库标记为 ,而它实际上并未在运行时环境中提供,这可能会导致运行时错误或类找不到的异常。
务必确定版本依赖和版本管理,否则容易出现冲突。
例子:比如在写缓存的 Starter 的时候,把 redis 的依赖设置成 provided。由引入的工程提供 redis
1.3 最新版本依赖
- 确保 Starter 不会带来与项目其他部分依赖冲突的库。可以统一公司的版本。
- 尽量减少 Starter 的依赖,避免不必要的依赖,以减少应用程序的启动时间和资源消耗。只包括实现功能所必需的依赖库。
- 版本包应该遵循 Jar 的规范,线上避免使用 SNAPSHOT 包。
二、编码细节
2.1 命名规范
- 官方定义的 Starter 通常命名遵循的格式为 spring-boot-starter-{name},例如 spring-boot-starter-data-redis。
- 非官方 Starter 命名应遵循 {name}-spring-boot-starter 的格式,例如,simplecache-spring-boot-starter
2.2 扩展性
- 通过 xxxProperties 等增加扩展性
- 通过条件注解实现按需加载
三、兼容性
尽量保持与旧版本的兼容性。当进行更新时,应该注意不要破坏现有用户的配置和使用方式。 由于 Starter 会升级,像 Jar 一样,因此需要注意兼容性,避免因为引入 Starter 而代理不兼容等问题。
不然升级将会异常灾难!
尽量保证版本的一致性,保持大版本的一致性会非常重要和关键。
四、其他注意事项
- 尽量不要在 Starter 中使用路径扫描 。类路径扫描不仅可能会扫描到不应该被注册的 bean,而且还会增加应用程序启动的时间。由于Spring Boot旨在简化开发,可能会引入一些不必要的依赖,导致应用启动慢或占用资源多。定期审查依赖和配置,剔除不需要的部分,是一个好习惯
- 在文档中清晰说明 Starter 的工作原理、如何配置以及如何与其他模块集成。文档应该详细到用户不需要查看代码就能理解和正确配置 Starter
- 使用
@Conditional
注解(如@ConditionalOnClass
、@ConditionalOnMissingBean
)来确保你的自动配置只有在满足特定条件时才加载。 - 虽然Spring Boot的“约定优于配置”大大简化了开发,但完全不理解背后的配置可能会导致问题难以排查。开发人员应该至少了解Spring Boot自动配置的基本原理
五、本章小结
了解这些细节后,接下来给出两个案例,在自己写 Starter 的时候,也一定要注意这些细节,否则它不是一个好的 Starter。
掘金账号:第九节 设计 SpringBoot Starter 不能忽视的细节 - 掘金 (juejin.cn)