Spring Boot 自定义 Starter
前面的代码中,无论是 Spring Boot 中使用 Web、Test,还是 MyBatis、Dubbo,都是通过导入一个相应的 Starter 依赖,然后由 Spring Boot 自动配置完成的。那么,如果我们自己的某项功能也想通过自动配置的方式应用到 Spring Boot 中,为 Spring Boot 项目提供相应支持,需要怎样实现呢?同样,我们需要定义自己的 Starter。
1. 手写 Starter
1.1 需求
下面我们自定义一个我们自己的 Starter,实现的功能是:为用户提供的字符串添加前辍与后辍,而前辍与后辍定义在 yml 或 properties 配置文件中。例如,用户输入的字符串为 China,application.yml 配置文件中配置的前辍为$$$
,后辍为+++
,则最终生成的字符串为$$$China+++
。
1.2 实现
A、创建工程
创建一个 Spring Boot 工程,命名为 wrap-spring-boot-starter,并导入 Configuration Processor 与 Lombok 依赖。
Spring Boot 官方给出的 Starter 工程的命名需要遵循如下规范
:
- Spring 官方定义的 Starter 格式为:spring-boot-starter-{name},如 spring-boot-starter-web。
- 非官方 Starter 命名格式为:{name}-spring-boot-starter,如 dubbo-spring-boot-starter。
导入的配置处理器依赖为:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
配置以后,在用@ConfigurationProperties的时候,如果配置类写好了成员属性,在配置文件里面会有友好提示。
B、 定义一个 Service 类
该 Service 类是当前 Starter 功能的核心类。其核心功能就是在这个类中完成的。该类中的成员变量可以随意命名,但一般与欲在 Spring Boot 中使用的属性名同名。
@AllArgsConstructor
public class WrapService {
private String before;
private String after;
// 核心业务方法
public String wrap(String word) {
return before + word + after;
}
}
C、 定义配置属性封装类
我们指定当前类用于封装来自于 Spring Boot 核心配置文件中的以 wrap.service 开头的 prefix 与 suffix 属性值。即用于封装配置文件中的如下属性值:
- wrap.service.prefix
- wrap.service.suffix
该类的对象是由系统自动创建,所以无需将其将给 Spring 容器管理。
// 要读取配置文件中wrap.service.prefix 与 wrap.service.suffix 两个属性的值
@Data
@ConfigurationProperties("wrap.service")
public class WrapServiceProperties {
private String prefix;
private String suffix;
}
D、定义自动配置类
为了加深对“自动配置类与配置文件属性关系”的理解,这里再增加一个功能:为wrap.service 再增加一个组装开关,一个 boolean 属性 enable,当 enable 属性值为 true 时,或没有设置 some.service.enable 属性时才进行组装,若 enable 为 false,则不进行组装。
/**
* 所谓自动配置,就是配置核心业务实例,或者说,是创建核心业务实例
*/
@Configuration
@ConditionalOnClass(WrapService.class)
@EnableConfigurationProperties(WrapServiceProperties.class)
public class WrapServiceAutoConfiguration {
@Autowired
private WrapServiceProperties properties;
@Bean
@ConditionalOnProperty(name = "wrap.service.enable", havingValue = "true", matchIfMissing = true)
// havingValue = "true" 表示如果wrap.service.enable值为true则条件成立
// 如果没有配havingValue的值,那么只要值不为"false",都认为条件成立!
// matchIfMissing 表示如果没有对应配置,那么默认是条件成立还是不成立
public WrapService wrapService() {
return new WrapService(properties.getPrefix(), properties.getSuffix());
}
// 注意在@Configuration的类中@Bean的创建是有顺序的
// 下面这个放到上面那么容器中就会有两个WrapService 实例
@Bean
@ConditionalOnMissingBean //容器中没有实例才会创建
public WrapService wrapService2() {
return new WrapService("", "");
}
}
E、 创建 spring.factories 文件
在 resources/META-INF 目录下创建一个名为 spring.factories 的文件。该配置文件是一个键值对文件,键是固定的,为 EnableAutoConfiguration 类的全限定性类名,而值则为我们自定义的自动配置类。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.abc.config.WrapServiceAutoConfiguration
2. 使用自定义的 Starter
在本地要使用我们自定义的 Starter,首先要保证其已经被 Install 到了本地 Maven 库。
(1) 创建工程
创建一个 Spring Boot 工程,仅需要一个 web 依赖。
(2) 导入自定义 Starter 依赖
<dependency>
<groupId>com.abc</groupId>
<artifactId>wraper-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
(3) 定义 properties.yml
自定义 Starter 中的属性在配置文件中也是有自动提示功能的。
wrap:
service:
enable: true # 开关
prefix: AAA-
suffix: -BBB
(4) 定义 Controller
@RestController
public class WrapController {
@Autowired
private WrapService service;
@RequestMapping("/wrap/{param}")
public String wrapHandler(@PathVariable("param") String param) {
return service.wrap(param);
}
}
(5) 运行访问
启动类无需修改,直接启动运行即可。