本文由 简悦 SimpRead 转码, 原文地址 juejin.cn
用了 springboot 那么久了居然都还没自定义过 starter,想想都觉得羞愧,所以今天来玩一下。
SpringBoot starter
SpringBoot 中的 starter 是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进 starter,应用者只需要在 maven 中引入 starter 依赖,SpringBoot 就能自动扫描到要加载的信息并启动相应的默认配置。starter 让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot 会自动通过 classpath 路径下的类发现需要的 Bean,并注册进 IOC 容器。SpringBoot 提供了针对日常企业应用研发各种场景的 spring-boot-starter 依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并允许我们调整这些配置,即遵循 “约定大于配置” 的理念。
自定义 starter
日常工作中有时有一些独立于业务之外的功能或模块,可能这个项目在用,另一个项目也要用,如果每次都重新集成的话就会很麻烦,这时我们只要把这些功能或模块封装成一个个 starter 的话,在使用的时候引入进去就很方便了。
自定义 starter 步骤
其实自定义 starter 很简单,大致需要以下 5 步:
- 新建两个模块,命名规范: springboot 自带的 starter 命名规范为 spring-boot-starter-xxx, 自定义的 starter 命名规范为 xxx-spring-boot-starter
● xxx-spring-boot-autoconfigure:自动配置核心代码
● xxx-spring-boot-starter:管理依赖
如果不需要将自动配置代码和依赖项管理分离开来,则可以将它们组合到一个模块中。只不过 springboot 官方建议将两个模块分开。
- 引入 spring-boot-autoconfigure 依赖
- 创建自定义的 XXXProperties 类: 这个类的属性根据需要是要出现在配置文件中的。
- 创建自定义的 XXXAutoConfiguration 类:这个类要配置自动配置时的一些逻辑,同时也要让 XXXProperties 类生效。
- 创建自定义的 spring.factories 文件:在 resources/META-INF 创建一个 spring.factories 文件和 spring-configuration-metadata.json,spring-configuration-metadata.json 文件是用于在填写配置文件时的智能提示,可要可不要,有的话提示起来更友好。spring.factories 用于导入自动配置类,必须要有
实现
我这里为了方便就只创建一个模块了,
- 创建一个模块,命名为 spring-boot-starter-my-starter,对应 pom 文件
<groupId>com.example</groupId>
<artifactId>spring-boot-starter-my-starter</artifactId>
<version>1.0</version>
<name>my-starter</name>
- 引入 spring-boot-autoconfigure 依赖 我这里使用的 spring-boot-autoconfigure 版本是 2.6.2
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>
- 创建自定义的 XXXProperties 类
@ConfigurationProperties(prefix = "com.arron")
public class MyStarterProperties {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
再创建一个 MyStarterConfig 用于读取 MyStarterProperties 里的属性
public class MyStarterConfig {
private MyStarterProperties myStarterProperties;
private String name;
public MyStarterConfig(MyStarterProperties myStarterProperties) {
this.myStarterProperties = myStarterProperties;
}
public String getName() {
return myStarterProperties.getName();
}
public void setName(String name) {
this.name = name;
}
}
- 创建自定义的 XXXAutoConfiguration 类
@Configuration
// EnableConfigurationProperties value数组中的配置类起作用
@EnableConfigurationProperties(value = {MyStarterProperties.class})
public class MyStarterAutoConfiguration {
@Autowired
private MyStarterProperties myStarterProperties;
@Bean
@ConditionalOnMissingBean(MyStarterConfig.class)
public MyStarterConfig myStarterConfig(){
return new MyStarterConfig(myStarterProperties);
}
}
- 在 resources/META-INF 创建一个 spring.factories 文件
spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.myStarter.MyStarterAutoConfiguration
spring-configuration-metadata.json
{
"group": [
{
"name": "com.arron",
"type": "com.example.myStarter.MyStarterProperties",
"sourceType": "com.example.myStarter.MyStarterProperties"
}
],
"properties": [
{
"name": "com.arron.name",
"type": "java.lang.String",
"description": "my start name",
"sourceType": "com.example.myStarter.MyStarterProperties",
"defaultValue": "MyStarterProperties name"
}
]
}
打包测试
找到如图 maven,点击 install,安装到本地
然后新建一个项目导包进行测试,创建项目过程就不介绍了。
- 引入依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-boot-starter-my-starter</artifactId>
<version>1.0</version>
</dependency>
- 配置文件添加属性:
com:
arron:
name: myname
- 单元测试:
@RunWith(SpringRunner.class)
@SpringBootTest
class RabbitmqApplicationTests {
@Autowired
private MyStarterConfig myStarterConfig;
@Test
public void testMyStarter(){
String name = myStarterConfig.getName();
System.out.println(name);
}
}
控制台输出:
myname
至此,一个简单自定义的 springboot starter 就完成了。
注解解释
下面这些注解在自定义 starter 是可能会用到。
- @Conditional:按照一定的条件进行判断,满足条件给容器注册 bean
- @ConditionalOnMissingBean:给定的在 bean 不存在时, 则实例化当前 Bean
- @ConditionalOnProperty:配置文件中满足定义的属性则创建 bean,否则不创建
- @ConditionalOnBean:给定的在 bean 存在时, 则实例化当前 Bean
- @ConditionalOnClass: 当给定的类名在类路径上存在,则实例化当前 Bean
- @ConditionalOnMissingClass :当给定的类名在类路径上不存在,则实例化当前 Bean