SpringBoot 从入门到光头 —— 第三章 了解自动配置原理
1. SpringBoot 特点
1.1. 依赖管理
父项目做依赖管理
依赖管理
<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>
SpringBoot 几乎声明了所有开发中常用的依赖的版本号,自动版本仲裁机制(以
web
为例)
开发导入
starter
场景启动器见到很多
spring-boot-starter-*
:*
就是某种场景只要引入
starter
,这个场景的所有常规需要的依赖我们都自动引入SpringBoot 所有支持的场景:
*-spring-boot-starter
: 第三方为我们提供的简化开发的场景启动器。所有场景启动器最底层的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.3.4.RELEASE</version> <scope>compile</scope> </dependency>
无需关注版本号,自动版本仲裁
- 引入依赖,默认都可以不写版本
- 引入非版本仲裁的
jar
,要写版本号。
可以修改默认版本号
查看
spring-boot-dependencies
里面规定当前依赖的版本用的key
在当前项目里面重写配置
<properties> <mysql.version>5.1.43</mysql.version> </properties>
1.2. 自动配置
自动配置好 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开发的常见场景
默认的包结构
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
无需以前的包扫描配置
想要改变扫描路径:
@SpringBootApplication(scanBasePackages = "com.yourname")
,或者通过@ComponentScan
指定扫描路径@SpringBootApplication // 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.yourname.boot")
各种配置拥有的默认值
- 默认配置最终都是映射到某个类上(如:
MultipartProperties
) - 配置文件的值最终会绑定每个类上,这个类会在容器中创建对象
- 默认配置最终都是映射到某个类上(如:
按需加载所有自动配置项
- 非常多的
starter
- 引入了哪些场景这个场景的自动配置才会开启
- SpringBoot 所有的自动配置功能都在
spring-boot-autoconfigure
包内
- 非常多的
…
2. 容器功能
2.1. 组件添加
1. @Configuration
- 基本使用
- Full 模式与 Lite 模式
- Full 模式:
@Configuration(proxyBeanMethods = true)
- Lite 模式:
@Configuration(proxyBeanMethods = false)
- 最佳实战
- 配置类组件之间无依赖关系用 Lite 模式加速容器启动过程,减少判断
- 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用 Full 模式
- Full 模式:
示例代码:
com.yourname.boot.bean.User
/**
* @author gregPerlinLi
* @since 2021-10-25
*/
public class User {
private String name;
private Integer age;
private Pet pet;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public User(String name, Integer age, Pet pet) {
this.name = name;
this.age = age;
this.pet = pet;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
com.yourname.boot.bean.Pet
/**
* @author gregPerlinLi
* @since 2021-10-25
*/
public class Pet {
private String name;
public Pet() {
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
com.yourname.boot.config.MyConfig
/**
* 1. <code>@Configuration</code>: Tell SpringBoot that this is a configuration class == configuration file
* <br/>2. Using <code>@Bean</code> in the configuration class can mark the method to register components for the container. By default, it is single instance
* <br/>3. The configuration class itself is also a component
* <br/>4. <code>proxyBeanMethod</code>: Method of proxy Bean
* <br/>Full: proxyBeanMethods = true
* <br/>Lite: proxyBeanMethods = false
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@Configuration(proxyBeanMethods = true)
public class MyConfig {
/**
* <code>@Bean</code>: Add components to container,take the method name as the ID of the component, the return type is the component type, The returned value is the instance of the component in the container
* <br/>No matter how many external calls are made to the component registration method in the configuration class, the single instance object in the previous registration container is obtained
*
* @return User
*/
@Bean
public User user01(){
User user = new User("XiaoMing", 18);
// The User component depends on the Pet component
user.setPet(tomcatPet());
return user;
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
com.yourname.boot.MainApplication
/**
* Main program class
* Main configuration class
*
* <br/><code>@SpringBootApplication</code>: This is a SpringBoot application
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@SpringBootApplication(scanBasePackages = "com.gregperlinli")
public class MainApplication {
public static void main(String[] args) {
// 1. Return an IOC container
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2. Components inside the container
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
// 3. Get component from container
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("Component: " + (tom01 == tom02));
// 4. com.gregperlinli.boot.config.MyConfig$$EnhancerBySpringCGLIB$$c49fbe8b@dc79225
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
// 5. If @Configuration (proxyBeanMethods = true) proxy object calls method, SpringBoot always checks whether the component is in the container
// Keep component single instance
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("The pet of user: " + (user01.getPet() == tom));
}
}
2. @Bean
、@Component
、@Controller
、@Service
、@Repository
根据它们的源码可以看到,@Controller
、@Service
、@Repository
其本质就是 @Component
它存在的本质只是给开发者看的,对 Spring 而言它们就都是 @Component
@Controller
控制层类,@Service
业务层类,@Repository
持久层类,@Component
无法归类到前三种时就称为组件
3. @ComponentScan
、@Import
示例代码:
com.yourname.boot.config.MyConfig
/**
* 1. <code>@Configuration</code>: Tell SpringBoot that this is a configuration class == configuration file
* <br/>2. Using <code>@Bean</code> in the configuration class can mark the method to register components for the container. By default, it is single instance
* <br/>3. The configuration class itself is also a component
* <br/>4. <code>proxyBeanMethod</code>: Method of proxy Bean
* <br/>Full: proxyBeanMethods = true
* <br/>Lite: proxyBeanMethods = false
* <br/>5. <code>@Import</code>: Automatically create components of the given type for the container. The default component name is the full class name
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true)
public class MyConfig {
/**
* <code>@Bean</code>: Add components to container,take the method name as the ID of the component, the return type is the component type, The returned value is the instance of the component in the container
* <br/>No matter how many external calls are made to the component registration method in the configuration class, the single instance object in the previous registration container is obtained
*
* @return User
*/
@Bean
public User user01(){
User user = new User("XiaoMing", 18);
// The User component depends on the Pet component
user.setPet(tomcatPet());
return user;
}
@Bean("tom")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
com.yourname.boot.MainApplication
/**
* Main program class<br/>
* Main configuration class
*
* <br/><code>@SpringBootApplication</code>: This is a SpringBoot application
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@SpringBootApplication(scanBasePackages = "com.gregperlinli")
public class MainApplication {
public static void main(String[] args) {
// 1. Return an IOC container
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2. Components inside the container
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
// 3. Get component from container
Pet tom01 = run.getBean("tom", Pet.class);
Pet tom02 = run.getBean("tom", Pet.class);
System.out.println("Component: " + (tom01 == tom02));
// 4. com.gregperlinli.boot.config.MyConfig$$EnhancerBySpringCGLIB$$c49fbe8b@dc79225
MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);
// 5. If @Configuration (proxyBeanMethods = true) proxy object calls method, SpringBoot always checks whether the component is in the container
// Keep component single instance
User user = bean.user01();
User user1 = bean.user01();
System.out.println(user == user1);
User user01 = run.getBean("user01", User.class);
Pet tom = run.getBean("tom", Pet.class);
System.out.println("The pet of user: " + (user01.getPet() == tom));
// 5. Get component
String[] beanNamesForType = run.getBeanNamesForType(User.class);
System.out.println("===============");
for (String s : beanNamesForType) {
System.out.println(s);
}
DBHelper bean1 = run.getBean(DBHelper.class);
System.out.println(bean1);
}
}
4. @Conditional
条件装配:满足 @Conditional
所指定的条件,则进行组件注入
@Conditional
注解家族:
示例代码:
com.yourname.boot.config.MyConfig
/**
* 1. <code>@Configuration</code>: Tell SpringBoot that this is a configuration class == configuration file
* <br/>2. Using <code>@Bean</code> in the configuration class can mark the method to register components for the container. By default, it is single instance
* <br/>3. The configuration class itself is also a component
* <br/>4. <code>proxyBeanMethod</code>: Method of proxy Bean
* <br/>Full: proxyBeanMethods = true
* <br/>Lite: proxyBeanMethods = false
* <br/>5. <code>@Import</code>: Automatically create components of the given type for the container. The default component name is the full class name
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true)
@ConditionalOnBean(name = "tom")
public class MyConfig {
/**
* <code>@Bean</code>: Add components to container,take the method name as the ID of the component, the return type is the component type, The returned value is the instance of the component in the container
* <br/>No matter how many external calls are made to the component registration method in the configuration class, the single instance object in the previous registration container is obtained
*
* @return User
*/
@Bean
public User user01(){
User user = new User("XiaoMing", 18);
// The User component depends on the Pet component
user.setPet(tomcatPet());
return user;
}
@Bean("tom22")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
com.yourname.boot.MainApplication
/**
* Main program class<br/>
* Main configuration class
*
* <br/><code>@SpringBootApplication</code>: This is a SpringBoot application
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@SpringBootApplication(scanBasePackages = "com.gregperlinli")
public class MainApplication {
public static void main(String[] args) {
// 1. Return an IOC container
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2. Components inside the container
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
boolean tom = run.containsBean("tom");
System.out.println("Is there a Tom component in the container: " + tom);
boolean user01 = run.containsBean("user01");
System.out.println("Is there a user01 component in the container: " + user01);
boolean tom22 = run.containsBean("tom22");
System.out.println("Is there a tom22 component in the container: " + tom22);
}
}
2.2. 原生配置文件引入
1. @ImportResource
示例代码:
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="haha" class="com.gregperlinli.boot.bean.User">
<property name="name" value="Zhangsan" />
<property name="age" value="18" />
</bean>
<bean id="hehe" class="com.gregperlinli.boot.bean.Pet">
<property name="name" value="tomcat" />
</bean>
</beans>
com.yourname.boot.config.MyConfig
/**
* 1. <code>@Configuration</code>: Tell SpringBoot that this is a configuration class == configuration file
* <br/>2. Using <code>@Bean</code> in the configuration class can mark the method to register components for the container. By default, it is single instance
* <br/>3. The configuration class itself is also a component
* <br/>4. <code>proxyBeanMethod</code>: Method of proxy Bean
* <br/>Full: proxyBeanMethods = true
* <br/>Lite: proxyBeanMethods = false
* <br/>5. <code>@Import</code>: Automatically create components of the given type for the container. The default component name is the full class name
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = true)
@ConditionalOnMissingBean(name = "tom")
@ImportResource("classpath:beans.xml")
public class MyConfig {
/**
* <code>@Bean</code>: Add components to container,take the method name as the ID of the component, the return type is the component type, The returned value is the instance of the component in the container
* <br/>No matter how many external calls are made to the component registration method in the configuration class, the single instance object in the previous registration container is obtained
*
* @return User
*/
@Bean
public User user01(){
User user = new User("XiaoMing", 18);
// The User component depends on the Pet component
user.setPet(tomcatPet());
return user;
}
@Bean("tom22")
public Pet tomcatPet() {
return new Pet("Tomcat");
}
}
com.yourname.boot.MainApplication
/**
* Main program class<br/>
* Main configuration class
*
* <br/><code>@SpringBootApplication</code>: This is a SpringBoot application
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@SpringBootApplication(scanBasePackages = "com.gregperlinli")
public class MainApplication {
public static void main(String[] args) {
// 1. Return an IOC container
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 2. Components inside the container
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
boolean haha = run.containsBean("haha");
boolean hehe = run.containsBean("hehe");
System.out.println("haha: " + haha + "\nhehe: " + hehe);
}
}
2.3. 配置绑定
如何使用 Java 读取到 properties
文件中的内容,并将其封装到 Java Bean 中,以供随时时使用
Java 原生实现方法:
public class getProperties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties pps = new Properties();
pps.load(new FileInputStream("a.properties"));
Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
while(enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
System.out.println(strKey + "=" + strValue);
//封装到JavaBean。
}
}
}
1. @Component
+ @ConfigurationProperties
com.yourname.boot.bean.Car
/**
* Only components in the container can use the functionality provided by springboot
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public Car() {
}
public Car(String brand, Integer price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
2. @EnableConfigurationProperties
+ @ConfigurationProperties
com.yourname.boot.bean.Car
/**
* Only components in the container can use the functionality provided by springboot
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public Car() {
}
public Car(String brand, Integer price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
com.yourname.boot.config.MyConfig
/**
* <br/>6. <code>@EnableConfigurationProperties</code>: Enable configure binding function, automatically register the specified component into the container
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@EnableConfigurationProperties(Car.class)
public class MyConfig {
}
3. 自动配置原理入门
3.1. 引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{
}
1. @SpringBootConfiguration
@Configuration
代表当前是一个配置类
2. @EnableAutoConfiguration
(重点)
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}
1. @AutoConfigurationPackage
自动配置包
@Import(AutoConfigurationPackages.Registrar.class) // 给容器中导入一个组件
public @interface AutoConfigurationPackage {
// 利用 Register 给容器中导入一系列组件
// 将指定的一个包下的所有组件导入进来(MainApplication所在的包下)
}
该注解利用了 Register
给容器中导入一系列组件,并将将指定的一个包下的所有组件导入进来(默认是在 MainApplication
所在的包下)
2. @Import(AutoConfigurationImportSelector.class)
利用
getAutoConfigurationEntry(annotationMetadata);
给容器中批量导入一些组件调用
ist<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
来获取所有需要导入到容器中的配置类利用工厂加载
Map<String, List<String>> loadSpringFactories(ClassLoader classLoader);
得到所有组件从
META-INF/spring.factories
位置来夹在一个文件。默认扫描当前系统里所有
META-INF/spring.factories
位置的文件spring-boot-autoconfigure-2.3.4.RELEASE.jar
包里面也有META-INF/spring.factories
在
spring.factories
中写死了一旦启动就要给容器中加在的所有配置文件# 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.Neo4jReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ 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.netty.NettyAutoConfiguration,\ 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.sql.init.SqlInitializationAutoConfiguration,\ 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
3. @ComponentScan
指定扫描那些目录,具体参考前面 Spring 中所讲到的
3.2. 按需开启自动配置项
虽然 131 个场景的所有配置启动的时候默认全部加载,但是按照条件装配规则(@Conditional
),最终会按需配置
3.3. 修改默认配置
以org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
为例:
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
上述类给容器中加入了文件上传解析器
@ConditionalOnBean(MultipartResolver.class)
:容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
: 容器中没有这个名字(multipartResolver
)的组件
给 @Bean
标注的方法传入了参数,这个参数的值就会从容器中找。
该方法防止某些用户配置的文件上传解析器不符合规范,将其名称修改为 multipartResolver
SpringBoot 默认会在底层配置好所有的组件,但是如果用户自己配置了,以用户的优先
以 org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
为例:
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}
总结:
SpringBoot 先加载所有的自动配置类
xxxAutoConfiguration
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值(在
xxxPoperties
类中获取,而该类又和配置文件application.properties
进行绑定)如果生效,生效的配置类就会给容器中装配组件
只要容器中有这个组件,相当于这些功能可以使用了
只要用户有自己配置的,就以用户的优先
定制化配置
- 用户直接自己使用
@Bean
替换底层组件 - 用户去看这个组件是获取配置文件的值,然后进行相应的修改
xxx-configuration
→ 组件 →xxxProperties
里面获取值 →application.properties
- 用户直接自己使用
3.4. 最佳实践
引入场景依赖
查看自动配置了那些组件(选做)
- 自己分析源码,引入场进对应的自动配置(一般都是生效的)
- 在自动配置文件中加入
debug=true
开启自动配置报告(其中Positive
下的是生效的组件,Negative
下的则为不生效的组件)
是否需要定制化
参照文档修改配置项
参考官网的配置文档:
自己分析,
xxxProperties
绑定了哪些配置文件
自定义加入或者替换组件
@Bean
、@Conponent
…
自定义器
xxxCustomizer
…
4. 开发技巧
4.1. Lombok
简化 Java Bean 以及日志开发
示例代码:
pom.xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
com.yourname.boot.bean.Car
/**
* Only components in the container can use the functionality provided by springboot<br/>
* <code>@NoArgsConstructor</code>: No arguments constructor<br/>
* <code>@AllArgsConstructor</code>: Full arguments constructor<br/>
*
* @author gregPerlinLi
* @since 2021-10-25
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
com.yourname.boot.bean.User
/**
* @author gregPerlinLi
* @since 2021-10-25
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class User {
private String name;
private Integer age;
private Pet pet;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
com.yourname.boot.bean.Pet
/**
* @author gregPerlinLi
* @since 2021-10-25
*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@EqualsAndHashCode
public class Pet {
private String name;
}
com.yourname.boot.controller.HelloController
/**
* @author gregPerlinLi
* @since 2021-10-25
*/
@RestController
@Slf4j
public class HelloController {
@Autowired
Car car;
@RequestMapping("/hello")
public String handle01(@RequestParam("name") String name){
log.info("Request in coming...");
return "Hello, SpringBoot2 " + "你好:" + name;
}
@RequestMapping("/car")
public Car car(){
return car;
}
}
注意⚠️:使用 Lombok 需要在 IDEA 上安装 Lombok 插件(新版的 IDEA 已经捆绑了 Lombok,无需自己安装)

4.2. Spring Initializer
Spring 项目初始化向导
创建项目
选择需要的开发环境
自动依赖注入
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </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>
自动创建项目结构
其中:
static
:放置静态资源templates
:放置所有的 Web 页面
自动编写主程序类
com.yourname.boot.Boot01Helloworld2Application
@SpringBootApplication public class Boot01Helloworld2Application { public static void main(String[] args) { SpringApplication.run(Boot01Helloworld2Application.class, args); } }
4.3. DevTools
主要实现 SpringBoot 的自动重启(当然也不止这个功能)
pom.xml
导入依赖坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
然后每当项目修改完之后,使用快捷键 ⌘F9(Windows 系统下则为:CtrlF9)进行自动重启
如果是需要热部署的话,则推荐使用 JRebel