我们使用 Spring Boot,基本上都是沉醉在它 Stater 的方便之中。Starter 为我们带来了众多的自动化配置,有了这些自动化配置,我们可以不费吹灰之力就能搭建一个生产级开发环境,有的小伙伴会觉得这个 Starter 好神奇呀!
其实 Starter 也都是 Spring + SpringMVC 中的基础知识点实现的,今天我们就 自己来写一个 Starter ,慢慢揭开 Starter 的神秘面纱!
自定义Starter
其实 Starter 的核心就是条件注解 @Conditional ,当 classpath 下存在某一个 Class 时,某个配置才会生效。
所谓的 Starter ,其实就是一个普通的 Maven 项目,因此我们自定义 Starter ,需要首先创建一个普通 的 Maven 项目,创建完成后,添加 Starter 的自动化配置类即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.7.RELEASE</version>
</dependency>
配置完成后,我们首先创建一个 HelloProperties 类,用来接受 application.properties 中注入的值, 如下:
@ConfigurationProperties(prefix = "tp")
public class HelloProperties {
private static final String DEFAULT_NAME = "TP";
private static final String DEFAULT_MSG = "渐行渐远";
private String name = DEFAULT_NAME;
private String msg = DEFAULT_MSG;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
这个配置类很好理解,将 application.yml 中配置的属性值直接注入到这个实例中, @ConfigurationProperties 类型安全的属性注入,即将 application.yml 文件中前缀为
tp 的属性注入到这个类对应的属性上, 最后使用时候,application.yml 中的配置文件, 大概如下:
tp:
name: zhangsan
msg: boot
配置完成 HelloProperties 后,接下来我们来定义一个 HelloService ,然后定义一个简单的 say 方法, HelloService 的定义如下:
public class HelloService {
private String msg;
private String name;
public String sayHello() {
return name + " say: " + msg + " !";
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这个很简单,没啥好说的。
接下来就是我们的重轴戏,自动配置类的定义,用了很多别人定义的自定义类之后,我们也来自己定义一个类。代码如下:
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
@ConditionalOnClass(HelloService.class)
public class HelloServiceAutoConfiguration {
@Autowired
private HelloProperties helloProperties;
@Bean
HelloService helloService(){
HelloService helloService = new HelloService();
helloService.setName(helloProperties.getName());
helloService.setMsg(helloProperties.getMsg());
return helloService;
}
}
关于这一段自动配置,解释如下:
- 首先 @Configuration 注解表明这是一个配置类。
- @EnableConfigurationProperties 注解是使我们之前配置的 @ConfigurationProperties 生效, 让配置的属性成功的进入 Bean 中。
- @ConditionalOnClass 表示当项目当前 classpath 下存在 HelloService 时,后面的配置才生效。 自动配置类中首先注入 HelloProperties ,这个实例中含有我们在 application.yml 中配置的相关数据。
- 提供一个 HelloService 的实例,将 HelloProperties 中的值注入进去。
做完这一步之后,我们的自动化配置类就算是完成了,接下来还需要一个 spring.factories 文件,那么这个文件是干嘛的呢? 大家知道我们的 Spring Boot 项目的启动类都有一个 @SpringBootApplication 注解,这个注解的定义如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
大家看到这是一个组合注解,其中的一个组合项就是 @EnableAutoConfiguration ,这个注解是干嘛的呢?
@EnableAutoConfiguration 表示启用 Spring 应用程序上下文的自动配置,该注解会自动导入一个名为 AutoConfigurationImportSelector 的类,而这个类会去读取一个名为 spring.factories 的文件, spring.factories 中则定义需要加载的自动化配置类,我们打开任意一个框架的 Starter ,都能看到它有 一个 spring.factories 文件,例如 druid 的 Starter 如下:
那么我们自定义 Starter 当然也需要这样一个文件,我们首先在 Maven 项目的 resources 目录下创建 一个名为 META-INF 的文件夹,然后在文件夹中创建一个名为 spring.factories 的文件,文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.tp.spring.boot.starter.config.HelloServiceAutoConfiguration
在这里指定我们的自动化配置类的路径即可,如此之后我们的自动化配置类就算完成了。
本地安装
在正常的公司开发中,我们可能需要将这个自定义starter发不到公司的maven私服,这里我们就简单起见,将这个starter直接安装到本地然后进行测试:
- 我们在前文中的boot-demo项目中引入我们自定义的stater:
<!-- 自定义starter -->
<dependency>
<groupId>com.tp</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0.0-snapshot</version>
</dependency>
- 编写测试类,测试:
@SpringBootTest
class BootDemoApplicationTests {
@Autowired
private HelloService helloService;
@Test
void starterTest(){
System.out.println(helloService.sayHello());
}
}
效果如下:
至此我们自定义一个starter就完成了