摘要
在大家使用Spring Boot进行开发的过程中,应该可以接触到Spring Boot提供的很多Starter。比如
spring-boot-starter-webspring-boot-starter-jdbc- …
Spring Boot AutoConfiguration原理
Auto Configuration类
在Spring Boot启动的过程中,会去找classpath:META-INF/spring.factories文件,来决定加载哪些AutoConfiguration类。
让我们看一下spring-boot-autoconfigure项目中的spring.factories文件。下面列出部分AutoConfiguration类。
1 | # Auto Configure |
Spring Boot会尝试去运行所有org.springframework.boot.autoconfigure.EnableAutoConfiguration列出的AutoConfiguration类。此处大家可以会有疑问,很多我在项目里没有用到。对应组件是不是也会被初始化?答案是不会。我们用RedisAutoConfiguration为例来看一下背后发生了什么。
1 |
|
- Line 1:
@Configuration定义Configuration组件 - Line 2:
@ConditionalOnClass(RedisOperations.class)在classpath中如果有RedisOperation类,则会运行此AutoConfiguration。反之则不会运行。 - Line 8:
@ConditionalOnMissingBean(name = "redisTemplate")如果在Spring容器中没有名为redisTemplate的Bean被注册,则执行redisTemplate()方法。反之则不会执行。
注:Spring Boot提供了一系列@Condition选择,同时还可以实现自定义Condition。参考Spring Boot - Condition Annotations
AutoConfiguration Hints
AutoConfiguration Hints功能主要便于开发人员在做配置时,IDE可以提示auto complete。如下截图:
Auto Complete信息包括:
- 配置名称
- 配置描述
- 配置默认值
具体信息在additional-spring-configuration-metadata.json中定义
创建自定义Starter
- 需要封装的Service类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class FooService {
private final String fooMessage;
private final String barMessage;
public FooService(String fooMessage, String barMessage) {
this.fooMessage = fooMessage;
this.barMessage = barMessage;
}
public String getFooMessage() {
return this.fooMessage;
}
public String getBarMessage() {
return this.barMessage;
}
} - AutoConfiguration类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package io.markfredchen.custom.starter.config;
import ...;
public class FooAutoConfiguration {
private String fooMessage;
private String barMessage;
public FooService fooService() {
return new FooService(fooMessage, barMessage);
}
} spring.factories1
2=\
io.markfredchen.custom.starter.config.FooAutoConfiguration- 默认配置
创建resources/config/foo.properties1
2=Foo!
=Bar!
使用自定义Starter
- 创建新项目
- SpringBootApplication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class FooApplication {
public static void main(String[] args) {
SpringApplication.run(FooApplication.class, args);
}
public CommandLineRunner runner(final FooService fooService) {
return args -> {
System.out.println(fooService.getFooMessage());
System.out.println(fooService.getBarMessage());
};
}
} pom.xml添加以下依赖1
2
3
4
5
6
7
8
9
10
11
12<dependencies>
<dependency>
<groupId>io.markfredchen</groupId>
<artifactId>foo-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
</dependencies>- 运行结果
1
2
3
4
5
6
72018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-11 11:28:55.548 INFO 23978 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-10-11 11:28:55.586 INFO 23978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-10-11 11:28:55.590 INFO 23978 --- [ main] i.m.c.s.foo.application.FooApplication : Started FooApplication in 1.725 seconds (JVM running for 2.44)
Foo!
Bar! - 覆盖默认配置
创建resources/application.properties1
foo.barMessage=Updated Bar!
- 运行结果
1
2
3
4
5
6
72018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-11 11:28:55.457 INFO 23978 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-10-11 11:28:55.548 INFO 23978 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-10-11 11:28:55.586 INFO 23978 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-10-11 11:28:55.590 INFO 23978 --- [ main] i.m.c.s.foo.application.FooApplication : Started FooApplication in 1.725 seconds (JVM running for 2.44)
Foo!
Updated Bar! - AutoConfiguration Hints
创建resources/META-INF/additional-spring-configuration-metadata.json效果1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16{
"properties": [
{
"name": "foo.fooMessage",
"type": "java.lang.String",
"description": "Foo Message.",
"defaultValue": "Foo!"
},
{
"name": "foo.barMessage",
"type": "java.lang.String",
"description": "Bar Message.",
"defaultValue": "Bar!"
}
]
}
参考
总结
本文介绍了spring boot starter机制以及如何创建自定义的starter。starter的目标是对现在有项目进行有效封装,减少开发人员的重复工作。
完整源代码访问GitHub