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应该有一下几个模块
autoconfigure
模块, 包含了自动装配的代码starter
模块, 提供了正常功能需要的依赖, 此依赖由autoconfigure
模块来进行装配
0.示例
https://gitee.com/spitman/my-starter
1. 命名
- 项目不要以
spring-boot
作为开头, 未来可能会和spring官方的starter起冲突
经验法则: 假设你在为 acme
业务编写starter, 那么你应该这样起名
autoconfigure
模块 :acme-spring-boot
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模块包含:
- 配置项
- 自动装配代码
- 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文件 在给配置项赋值的时候会给提示
下面有个例子:
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
/**
* Whether to check the location of acme resources.
*/
private boolean checkLocation = true;
/**
* Timeout for establishing a connection to the acme server.
*/
private Duration loginTimeout = Duration.ofSeconds(3);
public boolean isCheckLocation() {
return this.checkLocation;
}
public void setCheckLocation(boolean checkLocation) {
this.checkLocation = checkLocation;
}
public Duration getLoginTimeout() {
return this.loginTimeout;
}
public void setLoginTimeout(Duration loginTimeout) {
this.loginTimeout = loginTimeout;
}
}
2.2 自动装配代码
自动装配的代码, 也就是各种 @Configuration, @ConditionalOnXXX 配置的java类
示例:
/**
* 一个最简单的 自动装配的配置类
*/
@ConditionalOnClass(MyWeirdBean.class)
@Configuration
@EnableConfigurationProperties(MyConfigurationProperties.class)
public class MyWeirdBeanAutoConfiguration {
@Autowired
private MyConfigurationProperties myConfigurationProperties;
@Bean("bean1")
@ConditionalOnMissingBean(MyWeirdBean.class)
public MyWeirdBean getMyWeirdBean() {
return new MyWeirdBean(myConfigurationProperties.getThings());
}
}
所有feature的自动装配代码都写在autoconfigure模块中
为了让这些配置类能够在starter启动的时候加载, 需要在autoconfigure模块中配置 META-INF/spring.factories 文件, 告诉spring启动的时候主动加载这些配置类
示例:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.config.MyWeirdBeanAutoConfiguration,\
com.example.config.MyOtherBeanAutoConfiguration
2.3 maven依赖
必须的maven依赖:正常情况下autoconfigure模块中的其他feature的maven依赖一般需要标记为 <optional>true</optional>
这样starter模块引入autoconfigure 模块 只要提供依赖就加载配置, 不提供依赖则不加载配置, 调用方使用起来会非常方便
示例:
注意: 如果在应用中直接定义 autoconfigure模块的功能, 则需要配置 spring-boot-maven-plugin
防止repackage操作将依赖引入jar文件
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. starter模块
starter模块 编译后就是个空jar包
它存在的目的就是 提供自动装配必需的依赖 , 也就是说它一般只有一个pom.xml文件
4. 使用starter
使用方直接引入starter依赖即可