1. 第一个 SpringBoot 程序
-
选择要创建的项目类型及 JDK 版本
-
填写项目基本信息
-
选择依赖
-
选择项目位置
-
创建完项目结构如图所示
-
创建 HelloController
package com.ice.demo.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @RequestMapping("/hello") public String hello(){ return "Hello SpringBoot!"; } }
-
启动主类 DemoApplication
-
浏览器访问:127.0.0.1:8080/hello
2. 依赖管理特性
初始化项目的 pom.xml 文件长这样:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ice</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>第一个SpringBoot程序</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
可以发现,里面有 <parent>
标签,说明该工程是一个子工程,其父工程的 pom.xml 文件为:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
然后我们进入 spring-boot-starter-parent.pom 查看,主要包括如下设置:
-
项目信息(包括该父工程的开发者信息)
-
JDK 版本(JDK 8)
-
字符编码(UTF-8)
-
开源协议(Apache License)
-
静态资源过滤
<resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true</filtering> <includes> <include>**/application*.yml</include> <include>**/application*.yaml</include> <include>**/application*.properties</include> </includes> </resource> <resource> <directory>${basedir}/src/main/resources</directory> <excludes> <exclude>**/application*.yml</exclude> <exclude>**/application*.yaml</exclude> <exclude>**/application*.properties</exclude> </excludes> </resource> </resources>
-
编译打包插件
这里简要说下这个打包插件:
<executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer"> <resource>META-INF/spring.factories</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>${start-class}</mainClass> </transformer> </transformers> </configuration> </execution> </executions>
其实就是使用 maven-shade-plugin 插件打包,如果项目中用到了 Spring Framework,将依赖打到一个 jar 包中,运行时会出现读取 XML schema 文件出错. 原因是Spring Framework 的多个 jar 包中包含相同的文件 spring.handlers 和 spring.schemas,如果生成一个 jar 包会互相覆盖. 为了避免互相影响,可以使用 AppendingTransformer 来对文件内容追加合并.
并且,该文件也有一个父文件:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.3</version>
</parent>
进入 spring-boot-dependencies.pom 查看,可以发现包括两部分内容:
- 各种经常使用的工具包及其默认版本号
- 工具包相对应的 maven 依赖
可以在创建的项目的目录下的 pom.xml 中修改版本号来达到使用特定版本的目的
接下来再谈谈启动器,SpringBoot 已经内置了许多场景的启动器,其命名方式为 spring-boot-starters-*
,引入该场景的依赖后,自动会导入一系列相关依赖,无需像以前一样逐个导入.
以 web 场景为例:
- 没有的依赖可以在创建的项目目录下的 pom 文件中添加
- 已有的依赖允许替换版本
- 不建议替换 Spring 系列依赖的版本,他们一般与 SpringBoot 版本绑定
3. 项目结构
当一个类不包含包声明时,它被认为是在默认包中. 通常不鼓励使用默认包,应该避免使用. 对于 SpringBoot 应用程序来说,它可能会导致一些特殊的问题. 建议遵循 Java
推荐的包命名约定并使用反向的域名,例如:com.example.project
.
每个 SpringBoot 程序应当有一个主启动类,通常建议将主应用程序类放在根包中,置于其他类之上.
@SpringBootApplication
注解经常放在主类上,它隐式地为某些项定义了一个基本的“搜索包”,主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
典型的项目结构如下:
com
+- example
+- myapplication
+- Application.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
更改默认扫描包可以在 @SpringBootApplication
注解中传递参数:@SpringBootApplication(scanBasePackages="com.xxx.xxx")
@SpringBootApplication(scanBasePackages="com.ice.work")
等同于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.ice.work")
SpringBootApplication 注解其实是由下面三个注解封装的
4. 自动配置
SpringBoot 已经为我们配置好了许多功能:
-
自动配好Tomcat
-
引入 Tomcat 依赖
-
配置 Tomcat
<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 常见功能,如:字符编码问题
- SpringBoot 帮我们配置好了所有 web 开发的常见场景
-
各种配置拥有默认值
- 默认配置最终都是映射到某个类上,如:
MultipartProperties
- 配置文件的值最终会绑定某个类上,这个类会在容器中创建对象
- 默认配置最终都是映射到某个类上,如:
-
按需加载所有自动配置项
- 非常多的 starter
- 引入了哪些场景,这个场景的自动配置才会开启
- SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面
5. 容器功能
5.1 组件添加
首先创建两个实体类:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
private String name;
}
注意,学习的时候用 lombok 加快效率,实际开发别用.
传统的方法就是创建 beans.xml 进行配置:
<?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="user01" class="com.ice.demo.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="cat" class="com.ice.demo.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
下面看看新的基于注解的配置方法.
5.1.1 使用 @Configuration 注解
package com.ice.demo.config;
import com.ice.demo.bean.Pet;
import com.ice.demo.bean.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 1. 配置类里面使用 @Bean 标准在方法上给容器注册组件,默认是单实例的
* 2. 配置类本身也是组件
* 3. proxyBeanMethods:代理 bean 的方法,默认为 true
*/
@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {
@Bean
// 给容器中添加组件,以方法名作为组件的 id
// 返回类型就是组件类型
// 返回的值就是组件在容器中的实例
public User user01() {
return new User("zhangsan", 18);
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
然后,启动主程序:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 返回 IOC 容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
// 2查看容器里的组件
String[] names = run.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
可以看到容器中已经有杂合两个组件了:
这种方式仍然保证容器中组件是单实例的特性:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 返回 IOC 容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
// 从容器中获取组件
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println(tom01 == tom02); // true
// 配置类本身也是组件
// 如果@Configuration(proxyBeanMethods = true),获取到的是代理对象
// 此时获取组件时,如果容器中没有,则新创建一个,否则从从气质获取,保证组件单实例
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean); // com.ice.demo.config.MyConfig$$EnhancerBySpringCGLIB$$bacdb0d@3561304b
// 外部无论对配置类中的组件注册方法调用多少次,获取的都是之前容器中的单实例对象
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1); // true
}
}
输出结果:
true
com.ice.demo.config.MyConfig$$EnhancerBySpringCGLIB$$bacdb0d@3561304b
true
下面试验下 @Configuration(proxyBeanMethods = false)
的情况,其他代码不变,启动主类后输出的结果为:
true
com.ice.demo.config.MyConfig@248fb644
false
说明对于这段代码:
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean); // com.ice.demo.config.MyConfig@248fb644,可以看到不是代理对象了
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1); // false,此时拿到的也就不是相等的值了
引出 SpringBoot 的两种配置:Full
和 Lite
- Full:
@Configuration(proxyBeanMethods = true)
- Lite:
@Configuration(proxyBeanMethods = false)
主要用来解决组件依赖场景
修改一下 User
类:
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
再修改一下配置类:
@Configuration(proxyBeanMethods = true)
public class MyConfig {
@Bean
public User user01() {
User zhangsan = new User("zhangsan", 18);
// User 组件依赖了 Pet 组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
再次启动 SpringBoot:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 返回 IOC 容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println(user01.getPet() == tom); // true
}
}
输出结果为:
true
但是,我们如果设置 @Configuration(proxyBeanMethods = false)
输出的结果为:
false
这就是 SpringBoot 2 的一个大的改变,
Lite
模式的优点是可以跳过一些检查,对于无依赖场景加载会比较快,但是有依赖情况下,还是设置为Full
模式比较好.
5.1.2 传统注解
@Bean
、@Component
、@Controller
、@Service
、@Repository
这个不用多说了,包扫描到就能加载注册组件(@ComponentScan
)
5.1.3 @Import
这个在之前注解驱动开发有过笔记,见 Chapter 1.7
5.1.4 @Conditional
条件注册,满足 Condition
条件,则进行组件注册,该注解源码为:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
其继承树为:
ConditionalOnBean
:当容器中存在某些 bean 的时候才执行ConditionalOnMissingBean
:当容器中没有某些 bean 的时候才执行ConditionalOnClass
:当容器中有某个类的时候才执行ConditionalOnMissingClass
:当容器中没有某个类的时候才执行ConditionalOnResource
:当存在某些资源文件的时候才执行ConditionalOnJava
:在指定的 Java 版本号下才执行ConditionalOnWebApplication
:当项目是一个 web 应用的时候才执行ConditionalOnNotWebApplication
:当项目不是一个 web 应用的时候才执行ConditionalOnProperty
:当容器中存在某些属性的时候才执行ConditionalOnSingleCandidate
:当某些 bean 是单实例或者多实例但是存在@Primary
注解标注的 bean 的时候才执行
【例】配置类中值注册了 User
组件,但是没有注册 Pet
组件
@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {
@Bean
public User user01() {
User zhangsan = new User("zhangsan", 18);
zhangsan.setPet(tomcatPet());
return zhangsan;
}
// @Bean("tom")
// 此时只是常规方法,不是注册组件
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
此时执行主类:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 返回 IOC 容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
boolean tom = run.containsBean("tom");
System.out.println(tom); // false
boolean user01 = run.containsBean("user01");
System.out.println(user01); // true
}
}
现在希望容器中没有 Pet
组件时,也不要注册 User
组件,可以使用条件注解:
@Configuration(proxyBeanMethods = true) // 告诉 SpringBoot 这是一个配置类,等于一个配置类
public class MyConfig {
@Bean
@ConditionalOnBean(name = "tom")
public User user01() {
User zhangsan = new User("zhangsan", 18);
// User 组件依赖了 Pet 组件
zhangsan.setPet(tomcatPet());
return zhangsan;
}
// @Bean("tom")
public Pet tomcatPet() {
return new Pet("tomcat");
}
}
此时再执行主类方法:
false
false
5.2 原生配置文件引入
有些老的第三方包也许不支持注解形式,只能使用配置文件的方式,此时可以使用 @ImportResource
注解引入该配置文件
例如:
<?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="haha" class="com.ice.demo.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="hehe" class="com.ice.demo.bean.Pet">
<property name="name" value="tomcat"></property>
</bean>
</beans>
在配置类中如何引入呢?
@Configuration
@ImportResource("classpath:beans.xml")
public class MyConfig {
}
此时执行:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 返回 IOC 容器
ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println(haha); // true
System.out.println(hehe); // true
}
}
5.3 配置绑定
5.3.1 @Component + @ConfigurationProperties
我们写一个 Car
类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Component // 只有在容器中的组件,才会拥有 SpringBoot 容器提供的强大功能
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
}
配置文件这样写:
mycar.brand=BYD
mycar.price=100000
上面的含义是,将 Car
类注册到容器中,并且通过注解 @ConfigurationProperties
绑定配置文件中前缀为 mycar
的属性值到该组件的属性中.
注意,配置文件中的前缀之后的属性名必须和类中的属性名一致!
我们编写一个 Controller 来测试一下:
@RestController
public class CarController {
@Autowired
Car car; // 因为上面已经通过注解将该组件注册到容器中了,所以可以直接取
@RequestMapping("/car")
public Car car() {
return car;
}
}
网页显示:
5.3.2 @EnableConfigurationProperties + @ConfigurationProperties
此时 Car 类这样写:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
}
配置文件需要加一个注解,来指定哪个类开启配置绑定功能:
@Configuration
// 1. 开启 Car 配置绑定功能
// 2. 把 Car 组件注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
}
6. 自动配置原理入门
SpringBoot 的主程序类被 @SpringBootApplication
注解,其实核心等价于下面三个注解:
@SpringBootConfiguration
@EnableAutoConfigration
@ComponentScan
6.1 @SpringBootConfiguration
该注解源码为:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
它其实就是一个 @Configuration
,代表当前类是一个配置类,具体的见之前的博客,注解驱动开发
6.2 @ComponentScan
就是指定要扫描的包,排除的包,过滤的包
6.3 @EnableAutoConfigration
// 省略元注解
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
6.3.1 @AutoConfigurationPackage
// 省略元注解
@Import(AutoConfigurationPackages.Registrar.class) // 给容器中导入一个组件
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
进入 AutoConfigurationPackages.Registrar
类:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImports(metadata));
}
}
可以发现,其实就 2 个方法,registerBeanDefinitions()
是用来给容器中批量注册一些列组件的,在第 5 行打上断点:
其中,new PackageImports(metadata).getPackageNames()
是为了得到注解注释的类(其实就是主启动类)所在的包的全限定包名:
然后,就将该包下的所有组件都注册到容器中来.
6.3.2 @Import(AutoConfigurationImportSelector.class)
这里导入组件 AutoConfigurationImportSelector
用的是 @Import
的第二种方式,导入实现了 ImportSelector
接口的类.
这里面重写了selectImports()
方法:
- 该方法返回值就是要导入到容器中的全限定类名
AnnotationMetadata
包含了当前配置类的所有注解信息,不仅仅是@Import
上面重写方法是调用 getAutoConfigurationEntry()
方法得到一个结果,然后转成 String
数组返回.
所以我们要重点看看 getAutoConfigurationEntry()
这个方法.
进入该方法后,打上断点,debug 执行.
可以看到,函数内的一系列操作都是基于 configurations
列表的,该列表长度为 133 个:
这 130 个组件都要被导入到容器中.
为啥是这 130 个呢?就是通过方法 getCandidateConfigurations()
获取所有需要导入到容器中的组件(配置类).
如果你 Maven 里写的包有其他的,可能数目不一致
现在重新在该方法上打断点,进入该方法后,可以看到:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 利用工厂加载,最终调用SpringFactoriesLoader类中的
// Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) 方法得到所有的组件
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;
}
所以我们再进入到 loadSpringFactories()
方法中打断点:
可以看到之前几行都是空,然后进入到 try-catch 语句块,先调用 getResources()
方法加载一些资源文件:
我们看看资源文件的位置:
到这,可以理一下了,注册所有组件之前,要先从 META-INF/spring.factories
位置加载资源文件的,也就是默认扫描当前系统里所有 META-INF/spring.factories
位置的文件,例如 SpringBoot 的一些包,其中最重要的是下面这个 spring-boot-autoconfigure-2.4.4.jar
:
进入该资源文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration
配置项,可以看到写死了 SpringBoot 一启动要给容器中加载的所有配置类.
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.Neo4jReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
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.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.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
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
虽然我们 130 个场景的所有自动配置名称,启动的时候默认全部加载,但是最终会按照条件装配规则,按需注册,用到的就是 @Conditional
一系列条件装配的注解.
6.4 总结
- SpringBoot 先加载所有的配置类
- 每个自动配置类按照条件生效
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 只要有用户自己配置的,以用户自定义的为先
- 定制化配置
- 用户直接自己写一个
@Bean
替换底层的组件 - 配置文件设置自定义的属性值
- 用户直接自己写一个
6.5 注释处理器
IDEA 自定义类想要在配置文件中有代码提示的话需要导入一个 processor 包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
但是,这只是在开发时候有用,打包时我们不应该将该插件打包进项目中:
<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>