https://docs.spring.io/spring-boot/docs/2.5.x/reference/html/features.html#features.developing-auto-configuration https://docs.spring.io/spring-boot/docs/2.5.x/reference/html/features.html#features.developing-auto-configuration.custom-starter https://github.com/snicoll/spring-boot-master-auto-configuration

一个自定义的starter应该有一下几个模块

  1. autoconfigure 模块, 包含了自动装配的代码
  2. starter 模块, 提供了正常功能需要的依赖, 此依赖由 autoconfigure模块来进行装配

0.示例

https://gitee.com/spitman/my-starter

1. 命名

  • 项目不要以 spring-boot 作为开头, 未来可能会和spring官方的starter起冲突

经验法则: 假设你在为 acme 业务编写starter, 那么你应该这样起名

  1. autoconfigure 模块 : acme-spring-boot
  2. starter 模块 : acme-spring-boot-starter

如果autoconfigure模块没有也行, 直接将自动装配的代码写到starter模块中

1.1 多种feature的项目

将starter分为feature和starter两个模块不是必须的,
如果 acme 具有多种可选特性feature, 那么最好把autoconfigure模块与starter模块分开
然后每个feature, 创建一个starter
例如:

  • redis模块的starter: acme-spring-boot-starter-redis
  • jpa模块的starter: acme-spring-boot-starter-jpa
  • mq模块的starter: acme-spring-boot-starter-mq

所有feature的自动装配代码都放入 autoconfigure模块中
所有starter都依赖autoconfigure模块, 但是各个starter只引入该feature功能需要的依赖
例如:

  • acme-spring-boot-starter-redis: 依赖 autoconfigure模块, 和 jedis
  • acme-spring-boot-starter-jpa: 依赖 autoconfigure模块, 和 jpa
  • acme-spring-boot-starter-mq: 依赖 autoconfigure模块, 和 mq

这样其他应用引入你自定义的starter的时候可以更清晰的确定引入的功能

  • autoconfigure项目中的各种feature的Maven依赖设置为 true 的, 然后将所有的starter的自动装配代码写在此项目中
  • 具体的 starter 模块提供真正的feature依赖

这样autoconfigure中的配置, 可以按应用的依赖的starter进行有选择的加载

1.2 只有一种feature的项目

但如果**autoconfigure****starter**不区分可选特性, 那么直接合并为一个**starter**工程也是非常好的选择


2. autoconfigure 模块

autoconfigure模块包含:

  1. 配置项
  2. 自动装配代码
  3. maven依赖

2.1 定义配置项

一般每个starter都会有自己需要的配置项,
这些配置项使用方可以在application.properties中赋值配置项的key,
不要使用 Spring Boot 常用的键 (such as server, management, spring, and so on)未来保不齐spring新的配置项就和你重复了

经验法则:
前缀最好使用你项目的名字,
比如acme ,
确保你的配置项都有文档, 并对每个属性添加了javadoc, 这样添加 spring-boot-configuration-processor 依赖的时候, 编译时会自动生成 META-INF/spring-autoconfigure-metadata.properties文件,
使用方的IDE会读取META-INF/spring-autoconfigure-metadata.properties文件 在给配置项赋值的时候会给提示

下面有个例子:

  1. import java.time.Duration;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. @ConfigurationProperties("acme")
  4. public class AcmeProperties {
  5. /**
  6. * Whether to check the location of acme resources.
  7. */
  8. private boolean checkLocation = true;
  9. /**
  10. * Timeout for establishing a connection to the acme server.
  11. */
  12. private Duration loginTimeout = Duration.ofSeconds(3);
  13. public boolean isCheckLocation() {
  14. return this.checkLocation;
  15. }
  16. public void setCheckLocation(boolean checkLocation) {
  17. this.checkLocation = checkLocation;
  18. }
  19. public Duration getLoginTimeout() {
  20. return this.loginTimeout;
  21. }
  22. public void setLoginTimeout(Duration loginTimeout) {
  23. this.loginTimeout = loginTimeout;
  24. }
  25. }

还有一些建议

2.2 自动装配代码

自动装配的代码, 也就是各种 @Configuration, @ConditionalOnXXX 配置的java类
示例:

  1. /**
  2. * 一个最简单的 自动装配的配置类
  3. */
  4. @ConditionalOnClass(MyWeirdBean.class)
  5. @Configuration
  6. @EnableConfigurationProperties(MyConfigurationProperties.class)
  7. public class MyWeirdBeanAutoConfiguration {
  8. @Autowired
  9. private MyConfigurationProperties myConfigurationProperties;
  10. @Bean("bean1")
  11. @ConditionalOnMissingBean(MyWeirdBean.class)
  12. public MyWeirdBean getMyWeirdBean() {
  13. return new MyWeirdBean(myConfigurationProperties.getThings());
  14. }
  15. }

所有feature的自动装配代码都写在autoconfigure模块中
为了让这些配置类能够在starter启动的时候加载, 需要在autoconfigure模块中配置 META-INF/spring.factories 文件, 告诉spring启动的时候主动加载这些配置类

示例:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  2. com.example.config.MyWeirdBeanAutoConfiguration,\
  3. com.example.config.MyOtherBeanAutoConfiguration

2.3 maven依赖

必须的maven依赖:图片.png正常情况下autoconfigure模块中的其他feature的maven依赖一般需要标记为 <optional>true</optional>
这样starter模块引入autoconfigure 模块 只要提供依赖就加载配置, 不提供依赖则不加载配置, 调用方使用起来会非常方便

示例:
图片.png

注意: 如果在应用中直接定义 autoconfigure模块的功能, 则需要配置 spring-boot-maven-plugin 防止repackage操作将依赖引入jar文件

  1. <project>
  2. <build>
  3. <plugins>
  4. <plugin>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-maven-plugin</artifactId>
  7. <configuration>
  8. <excludes>
  9. <exclude>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-autoconfigure-processor</artifactId>
  12. </exclude>
  13. </excludes>
  14. </configuration>
  15. </plugin>
  16. </plugins>
  17. </build>
  18. </project>

3. starter模块

starter模块 编译后就是个空jar包
它存在的目的就是 提供自动装配必需的依赖 , 也就是说它一般只有一个pom.xml文件
图片.png

4. 使用starter

使用方直接引入starter依赖即可图片.png