我们知道在使用springboot的时候,都会我们只需要在application.yml或者application.properties中指定配置参数就可以使用,那这是如何实现的,本篇文章就通过一个简单例子来解释springboot是如何实现自动配置。
假设,现在项目需要一个功能,需要自动记录项目发布者的相关信息,我们如何通过 Spring Boot 的自动配置,更好的实现功能呢?
maven 环境搭建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhangke.www</groupId> <artifactId>SimpleDemoSpringBootAutoConfiguration</artifactId> <version>1.0-SNAPSHOT</version>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.0.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.0.4.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.11.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure-processor</artifactId> <version>2.0.4.RELEASE</version> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
开发自动配置模块,需要引入spring-boot-autoconfigure这个模块,具体的可以参考spring boot 官网
参数配置
回想一下,当我们在spring中是如何使用数据库,首先需要创建一个数据库Datasource的Bean,但是我们需要填入数据库连接需要的配置选项,类如数据库用户名,密码等。
参数配置就有点类似于数据库连接中的配置选项,这里的配置参数,可以通过application.yml中直接设置。然后我们可以在需要的地点使用这个配置bean。
具体demo代码如下
1 2 3 4 5 6 7 8 9 10 11
| @ConfigurationProperties(prefix = "custom") public class AuthorProperties { public static final String DEFAULT_AUTHOR = "LiangGzone"; public String author = DEFAULT_AUTHOR; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
|
看到上面你应该能想到如何在application.yml配置参数的时候,向下面这样配置,这个属性bean就能正确读到配置
1 2
| custom: author = zhangke
|
简单服务类–自动记录项目发布者的相关信息
1 2 3 4 5 6 7 8 9 10
| public class AuthorServer { public String author; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
|
这段代码没什么高级的地点,就是简单的写了一个bean用来记录信息。
自动配置的核心 - 自动配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration @ConditionalOnClass({ AuthorServer.class }) @EnableConfigurationProperties(AuthorProperties.class) public class AuthorAutoConfiguration { @Resource private AuthorProperties authorProperties; @Bean @ConditionalOnMissingBean(AuthorServer.class) public AuthorServer authorResolver() { AuthorServer authorServer = new AuthorServer(); authorServer.setAuthor(authorProperties.getAuthor()); return authorServer; } }
|
我们一起来看这段代码,首先是类上面的注解:
- @Configuration : 这个没什么好解释的,表明这是一个注解
- @ConditionalOnClass:参数中对应的类在 classpath 目录下存在时,才会去解析对应的配置类。因此,我们需要配置 AuthorServer 。
- @EnableConfigurationProperties: 用来加载配置参数,所以它应该就是属性参数类 AuthorProperties。
然后看一下类中的注解
- @Resource: 将指定的bean添加进来
- @ConditionalOnMissingBean,用来确定当IOC容器中没有指定类型的Bean,才会去创建对应的bean
- @ConditionalOnProperty这个主要是用来检测配置文件中
custom.author.enabled
的值是否和
authorResolver方法的作用,即 AuthorProperties 的参数赋值到AuthorServer 中。
从上面我们可以看到,使用了几个@ConditionalOn*
的注解,这几个注解主要是用来检测某一个条件是否匹配
比较常用的还有下面几个类:
1 2 3 4 5 6
| @ConditionalOnWebApplication : web环境 @ConditionalOnNotWebApplication : 条件是当前不是web应用 @ConditionalOnProperty : 检查特定属性是否已经配置了特定值 @ConditionalOnResource : 检查特定的资源是否已经在类路径下 @ConditionalOnMissingClass : 不包含某个类 @ConditionalOnSingleCandidate: 表示只能有一个候选bean,如果超过一个,可以使用@Primary指定首选,这样才不会抛出异常
|
spring.factories 不要遗漏
我们需要实现自定义自动装配,就需要自定义spring.factories 参数。所以,我们需要在 src/main/resources/ META-INF/spring.factories
中配置信息,值得注意的是,这个文件要自己创建。
1 2 3
| org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 替换成你当前的包名.AuthorAutoConfiguration表示的是
|
如果你知道SPI,那么就能很容易的理解这段代码,其实就是指定需要加载的类,只不过这个是spring自己实现的一套类似于SPI的标准。spring启动时,会自动解析这个文件。根据条件加载对应的自动配置类。
功能打包与配置依赖
好了,我们已经实现了一个简单的自动配置功能。那么,我们需要将这个项目打成 jar 包部署在我们的本地或者私服上。然后,就可以用了。
我们在另外一个项目中,配置 Maven 依赖。
1 2 3 4 5
| <dependency> <groupId>com.zhangke.www</groupId> <artifactId>springboot-action-autoconfig</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
|
测试,测试
第一种测试方法,是你在写一个springboot的web应用,然后写下面这个控制器,检测自动配置是否已经正确实现。
1 2 3 4 5 6 7 8 9 10 11 12
| @RestController @EnableAutoConfiguration public class AuthorAutoConfigDemo {
@Resource private AuthorServer authorServer;
@RequestMapping("/custom/author") String home() { return "发布者:"+ authorServer.getAuthor(); } }
|
运行起来,我们看下打印的发布者信息是什么?
我们在 application.properties 中配置一个信息。
1 2
| #custom custom.author = zhangke
|
还有一种是springboot2.0新增加的一个特性,直接在当前的项目中写一个测试来判断自动配置功能是否成功。
具体代码如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class autoConfigureTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(AuthorAutoConfiguration.class)) .withPropertyValues("custom.author=zhangke", "custom.author.enabled=true");
@Test public void test() { this.contextRunner.run((context) -> { assertThat(context).hasSingleBean(AuthorServer.class); assertThat(context.getBean(AuthorServer.class).getAuthor()).isEqualTo("zhangke");
}); }
}
|
继续完善代码–配置元数据
回想一下,当我们在使用IDE编辑application.yml文件时,会有自动提示。这是怎么做出来呢,其实很简单,只需要创建如下文件src/main/resources/ META-INF/spring-configuration-metadata.json
具体内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "groups": [ { "name": "custom", "type": "simpleDemo.AuthorProperties", "sourceType": "simpleDemo.AuthorProperties" } ], "properties": [ { "sourceType": "simpleDemo.AuthorProperties", "name": "custom.author", "type": "java.lang.String" } ] }
|
具体配置可以参考如下链接
spring boot 官网配置元数据
配置元数据
另外我们有一些参数可能在配置的时候不需要,并且也很少用到,或者有一些需要废除的配置选项,可以创建如下文件src/main/resources/ META-INF/additional-spring-configuration-metadata.json
,然后按照上面的格式写上对应的信息。
参考
- Spring Boot揭秘与实战 自己实现一个简单的自动配置模块
- spring boot 官网配置元数据
- 配置元数据