Spring Boot官方文档

基础入门

Spring

  • Web 开发
  • 数据访问
  • 安全控制
  • 分布式
  • 消息服务
  • 移动开发
  • 批处理

Why Spring Boot

  1. 能够创建独立的 Spring 应用
  2. 内嵌 Web 服务器
  3. 自动 starter 依赖,简化构建配置
  4. 自动配置 Spring 以及第三方功能
  5. 提供生产级别的监控、健康检查及外部化配置
  6. 没有代码生成,不需要 XML 配置
  7. SpringBoot 是整合 Spring 技术栈的一站式框架
  8. SpringBoot 是简化 Spring 技术栈的快速开发脚手架

时代背景

微服务

微服务是一种架构风格,将一个应用拆分为一组小型服务,每个服务运行在自己的进程内,也就是可独立部署和升级,服务之间使用轻量级 HTTP 交互,服务围绕业务功能拆分,可以由全自动部署机制独立部署,去中心化,服务自治。服务可以使用不同的语言、不同的存储技术。

分布式困难

  • 远程调用
  • 服务发现
  • 负载均衡
  • 服务容错
  • 配置管理
  • 服务监控
  • 链路追踪
  • 日志管理
  • 任务调度
  • ……

分布式解决方案

SpringBoot + SpringCloud

云原生

Cloud Native

上云困难

  • 服务自愈
  • 弹性伸缩
  • 服务隔离
  • 自动化部署
  • 灰度发布
  • 流量治理
  • ……

上云解决方案

  1. 初识云原生
  2. 深入 Docker-容器化技术
  3. 掌握星际级容器编排 Kubernetes
  4. DevOps—实战企业 CI/CD,构建企业云平台
  5. 新一代架构 Service Mesh 与 Serverless

快速入门

我的第一个SpringBoot项目

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

编写启动类

1
2
3
4
5
6
7
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}

编写控制器

1
2
3
4
5
6
7
8
@RestController
public class HelloController {

@RequestMapping("/hello")
public String handler() {
return "Hello, SpringBoot 2.3.4 !";
}
}

打包部署

1
2
3
4
5
6
7
8
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

运行 clean 、package,把 helloworld 工程项目的打包成 jar 包,运行 java -jar boot-01-helloworld-1.0-SNAPSHOT.jar,即可以运行helloworld工程项目。

依赖管理

父项目进行依赖管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
依赖管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>

上面项目的父项目如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.4.RELEASE</version>
</parent>

它几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制

stater 场景启动器

  • 见到很多 spring-boot-starter-** 是某种场景

  • 只要引入 starter,这个场景的所有常规需要的依赖都自动引入

  • 更多场景请点我

  • 见到的 *-spring-boot-starter : 第三方为我们提供的简化开发的场景启动器

所有场景启动器最底层的依赖

1
2
3
4
5
6
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>

自动版本仲裁

  • 引入依赖默认可不写版本号
  • 引入非版本仲裁的依赖需要写版本号

修改默认版本号

1
2
3
<properties>
<mysql.version>5.1.43</mysql.version>
</properties>

自动配置

自动配置 Tomcat

引入 Tomcat 依赖,配置它

1
2
3
4
5
6
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.3.4.RELEASE</version>
<scope>compile</scope>
</dependency>

自动配置 SpringMVC

  • 引入 SpringMVC 全套组件
  • 自动配好 SpringMVC 常用组件(功能)

自动配置 Web 常见功能

Spring Boot 帮我们配置好了所有 web 开发的常见场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

// 查看容器组件
String[] names = run.getBeanDefinitionNames();

for (String name : names) {
System.out.println(name);
}
}
}

默认包结构

  1. 主程序所在包及其下面的所有子包 里面的组件都会被默认扫描进来,无需以前的包扫描配置
  2. 想要改变扫描路径
    • @SpringBootApplication(scanBasePackages="com.cyan")
    • @ComponentScan 指定扫描路径
1
2
3
4
5
@SpringBootApplication
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.cyan")

各种配置拥有默认值

  • 默认配置最终都是映射到某个类上,如:MultipartProperties
  • 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象

按需加载所有自动配置项

非常多的 starter,引入了哪些场景这个场景的自动配置才会开启,SpringBoot所有的自动配置功能都在 spring-boot-autoconfigure 包里面

底层注解

@Configuration

@Configuration:配置类,取代配置文件,配置类本身是组件

属性 说明
proxyBeanMethods 代理Bean的方法
@Configuration(proxyBeanMethods = true) 外部无论对配置类的组件注册方法调用多少次,获取的都是之前容器中注册的单实例对象每次启动SpringBoot检查方法返回的对象在容器中有没有
@Configuration(proxyBeanMethods = false) 不会检查方法返回的对象在容器中有没有,SpringBoot启动运行比较快

@Configuration(proxyBeanMethods = true)

MyConfig 是被 SpringCGLIB 增强了的代理对象,获取的本身就是代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

// MyConfig是被SpringCGLIB增强了的代理对象,获取的本身就是代理对象
MyConfig bean = run.getBean(MyConfig.class);
// com.cyan.boot.config.MyConfig$$EnhancerBySpringCGLIB$$166e7ae6@4fbb001b
System.out.println(bean);
}
}
1
2
3
4
5
6
7
8
9
10
@Configuration(proxyBeanMethods = true)
public class MyConfig {

@Bean
public User fun1() {
User cyan = new User("CyanChau", 18);
return cyan;
}

}

如果 @Configuration(proxyBeanMethods = true),该类获取到的是代理对象调用方法。SpringBoot 总会检查这个组件是否在容器中有没有该方法以及返回的组件,如果容器中有,直接拿;如果没有,再来调用、创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

// MyConfig是被SpringCGLIB增强了的代理对象,获取的本身就是代理对象
MyConfig bean = run.getBean(MyConfig.class);
// com.cyan.boot.config.MyConfig$$EnhancerBySpringCGLIB$$166e7ae6@4fbb001b
System.out.println(bean);

User user1 = bean.fun1();
User user2 = bean.fun1();

// 比较两实例 true
System.out.println(user1==user2);
}
}

总结:保持组件单实例

@Configuration(proxyBeanMethods = false)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration(proxyBeanMethods = false)
public class MyConfig {

@Bean
public User fun1() {
User cyan = new User("CyanChau", 18);
return cyan;
}

@Bean
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

// MyConfig是被SpringCGLIB增强了的代理对象,获取的本身就是代理对象
MyConfig bean = run.getBean(MyConfig.class);

// com.cyan.boot.config.MyConfig@2fb69ff6
System.out.println(bean);

User user1 = bean.fun1();
User user2 = bean.fun1();

// 比较两实例 false
System.out.println(user1==user2);
}
}

类组件依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration(proxyBeanMethods = true)
public class MyConfig {

@Bean("fun1")
public User fun1() {
User cyan = new User("CyanChau", 18);
// fun1组件依赖Pet组件
cyan.setPet(tomcatPet());
return cyan;
}

@Bean("tom")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

User user = run.getBean("fun1", User.class);
Pet tom = run.getBean("tom", Pet.class);

// 返回true
System.out.println("用户的宠物:"+(user.getPet() == tom));
}
}

如果 @Configuration(proxyBeanMethods = true) 结果返回true,如果 @Configuration(proxyBeanMethods = false) 返回false

两种模式

  • Full[ @Configuration(proxyBeanMethods = true) ]模式
  • Lite[ @Configuration(proxyBeanMethods = false) ]模式
  • 配置 类组件之间 无依赖关系 用 Lite 模式加速容器启动过程,减少判断
  • 配置 类组件之间 有依赖关系,方法会被调用得到之前单实例组件,用Full模式 (默认)
  • 应用场景:解决组件依赖

@Bean

  • 给容器中添加组件,以方法名作为组件的 id。返回类型为组件类型。返回值是组件在容器中的实例
  • 自定义组件名:@Bean("name")
  • 配置类里面使用@Bean标注在方法上给容器注册组件,默认是单实例的

@Import

注解 说明
@Import({User.class, DBHelper.class}) 给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false)
public class MyConfig {

@Bean("fun1")
public User fun1() {
User cyan = new User("CyanChau", 18);
// fun1组件依赖Pet组件
cyan.setPet(tomcatPet());
return cyan;
}

@Bean("tom")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
public class MainApplication {

public static void main(String[] args) {
// 返回IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

// 获取组件
String[] names = run.getBeanNamesForType(User.class);
for (String name : names) {
System.out.println(name);
}

DBHelper dbHelper = run.getBean(DBHelper.class);
System.out.println(dbHelper);
}
}

控制台输出

com.cyan.boot.entity.User
fun1(之前注入的)
ch.qos.logback.core.db.DBHelper@1929425f

@Conditional

注解 说明
@Conditional 条件装配:满足Conditional指定的条件,则进行组件注入

ConditionalOnBean

当容器中存在Tom组件fun1才生效,用于方法和类上同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration(proxyBeanMethods = false)
public class MyConfig {

@Bean("fun1")
@ConditionalOnBean(name = "Tom")
public User fun1() {
User cyan = new User("CyanChau", 18);
// fun1组件依赖Pet组件
cyan.setPet(tomcatPet());
return cyan;
}

//@Bean("tom")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
1
2
3
4
5
6
// false
boolean fun1 = run.containsBean("fun1");
System.out.println(fun1);
// false
boolean tom = run.containsBean("tom");
System.out.println(tom);

@ImportResource

注解 说明
@ImportResource 导入Spring配置文件

application-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="u1" class="com.cyan.boot.entity.User">
<property name="name" value="gress"></property>
<property name="age" value="18"></property>
</bean>

<bean id="u2" class="com.cyan.boot.entity.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>

config

1
2
3
@Configuration(proxyBeanMethods = false)
@ImportResource("classpath:application-context.xml")
public class MyConfig {
1
2
3
4
boolean u1 = run.containsBean("u1");
boolean u2 = run.containsBean("u2");
System.out.println("u1:"+u1); // true
System.out.println("u2:"+u2); // true

@ConfigurationProperties

读取 properties 文件

使用 Java 读取到 properties 文件中的内容,并且把它封装到 JavaBean 中,以供随时使用

传统方式

1
2
3
4
5
6
7
Properties properties = new Properties();
properties.load(new FileInputStream("db.properties"));

String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
System.out.println("driver-==-="+driver);
System.out.println("url-==-="+url);

SpringBoot 配置绑定1 @ConfigurationProperties + @Component

1
2
mycar.brand=BYD
mycar.price=100000
1
2
3
4
5
6
7
8
9
10
11
@Data
@Component
@ConfigurationProperties(prefix = "mycar")
@AllArgsConstructor
@NoArgsConstructor
public class Car {

private String brand;

private Integer price;
}
1
2
3
4
5
6
7
8
9
10
@RestController
public class CarController {
@Autowired
private Car car;

@RequestMapping("/car")
public Car car() {
return car;
}
}

只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能

SpringBoot 配置绑定2 @EnableConfigurationProperties + @ConfigurationProperties

只能在配置类里面写

  1. 开启Car配置绑定功能
  2. 把这个Car这个组件自动注册到容器中
1
2
3
4
5
@Configuration
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
1
2
3
4
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}

自动配置原理

自动包规则原理

@SpringBootApplication

1
2
3
4
5
6
7
8
9
10
11
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}

@SpringBootConfiguration

1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(annotation = Configuration.class)
boolean proxyBeanMethods() default true;
}

当前是一个配置类

@ComponentScan

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

指定扫描哪些Spring注解

@EnableAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

Class<?>[] exclude() default {};

String[] excludeName() default {};
}

@AutoConfigurationPackage 自动配置包,指定了默认的包规则。

1
2
3
4
5
6
7
8
9
10
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)//给容器中导入一个组件
public @interface AutoConfigurationPackage {
String[] basePackages() default {};

Class<?>[] basePackageClasses() default {};
}

@AutoConfigurationPackage 原理总结

  1. 利用Registrar给容器中导入一系列组件
  2. 将指定的一个包下的所有组件导入进MainApplication所在包下。

初始加载自动配置类

@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector

getAutoConfigurationEntry(annotationMetadata); // 给容器中批量导入一些组件

1
2
3
4
5
6
7
8
9
10
11
12
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
...
}

getAutoConfigurationEntry

List configurations = getCandidateConfigurations(annotationMetadata, attributes); // 获取到所有需要导入到容器中的配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations

1
2
3
4
5
6
7
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}

loadFactoryNames

利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件

1
2
3
4
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

loadSpringFactories

1
2
3
4
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
...
}

META-INF/spring.factories位置来加载一个文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件

spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories

文件里面写死了spring-boot一启动就要给容器中加载的所有配置类

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

按需加载配置

虽然我们127个场景的所有自动配置启动的时候默认全部加载,但是xxxxAutoConfiguration按照条件装配规则@Conditional),最终会按需配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.aop",
name = "auto",
havingValue = "true",
matchIfMissing = true
)
public class AopAutoConfiguration {
public AopAutoConfiguration() {
}
...
}

@Import(AutoConfigurationImportSelector.class) 原理总结

  1. 利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
  2. 调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
  3. 利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);得到所有的组件
  4. META-INF/spring.factories位置来加载一个文件。
    • 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
    • spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories

自动配置流程

SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先

文件上传解析器案例

Detect if the user has created a MultipartResolver but named it incorrectly

1
2
3
4
5
6
7
8
@Bean
@ConditionalOnBean(MultipartResolver.class) // 容器中有这个类型组件才生效
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)// 容器中不这样命名: multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// 给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找,此时到容器中去找MultipartResolver,然后给用户
// SpringMVC multipartResolver 防止有些用户配置的文件上传解析器不符合规范
return resolver;
}

自动配置流程总结

  1. SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
  2. 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
  3. 生效的配置类就会给容器中装配很多组件
  4. 只要容器中有这些组件,相当于这些功能生效了

个性化定制配置

  • 用户直接自己@Bean替换底层的组件
  • 用户去看这个组件是获取的配置文件什么值就去修改

HttpEncodingAutoConfiguration

1
2
3
4
5
6
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

ServerProperties

1
2
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {

xxxxxAutoConfiguration —-> 组件 —-> xxxxProperties里面拿值 ——> application.properties

xxxAutoConfiguration 中导入了很多的组件,然后这些组件从 xxxProperties 中拿到对应的默认值,然后 xxxProperties 是从 application.properties 配置文件中获取的值,所以一般情况下我们只要改配置文件,就可以修改所有的默认行为。

配置文件

yaml

yml 的优先级会大于 properties,所以如果同时存在这两种配置,因为 properties 是后加载的,所以此时 yml 就没有生效

基本语法

  • key: value;kv之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • #‘表示注释
  • 字符串无需加引号,如果要加,''""表示字符串内容 会被 转义/不转义

单引号:会将\n作为字符串输出

双引号:会将\n作为换行输出

单引号会转义双引号不会转义

数据类型

数据类型 说明
字面量 单个的、不可再分的值。date、boolean、string、number、null
对象 键值对的集合。map、hash、set、object
数组 一组按次序排列的值。array、list、queue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 字面量
k: v

# 对象
# 行内写法:
k: {k1:v1,k2:v2,k3:v3}
# 或
k:
k1: v1
k2: v2
k3: v3

# 数组
# 行内写法:
k: [v1,v2,v3]
# 或
k:
- v1
- v2
- v3

案例分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Data
@ToString
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}

@Data
public class Pet {
private String name;
private Double weight;
}
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
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
1
2
3
4
5
6
7
8
9
10
11
@RestController
public class PersonController {

@Autowired
private Person person;

@RequestMapping("/person")
public Person person() {
return person;
}
}
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
{
"userName":"zhangsan",
"boss":false,
"birth":"2019-12-12T12:12:33.000+00:00",
"age":18,
"pet":{
"name":"tomcat",
"weight":23.4
},
"interests":[
"篮球",
"游泳"
],
"animal":[
"jerry",
"mario"
],
"score":{
"english":{
"first":30,
"second":40,
"third":50
},
"math":{
"0":131,
"1":140,
"2":148
},
"chinese":{
"first":128,
"second":136
}
},
"salarys":[
3999,
4999.98,
5999.99
],
"allPets":{
"sick":[
{
"name":"tom",
"weight":null
},
{
"name":"jerry",
"weight":47
}
],
"health":[
{
"name":"mario",
"weight":47
}
]
}
}

自定义类绑定的配置提示

You can easily generate your own configuration metadata file from items annotated with @ConfigurationProperties by using the spring-boot-configuration-processor jar. The jar includes a Java annotation processor which is invoked as your project is compiled.——link

自定义的类和配置文件绑定一般没有提示。若要提示,添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<!-- 下面插件作用是工程打包时,不将spring-boot-configuration-processor打进包内,让其只在编码的时候有用 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>