springboot自动装配原理及基本注解
1、底层基本注解分析
@Import注解: 该注解是向spring容器中导入任意组件。
测试:用@Import 导入@Import({User.class, DBHelper.class})两个组件
package com.tain;
import ch.qos.logback.core.db.DBHelper;
import com.tain.config.MyConfig;
import com.tain.entity.Pet;
import com.tain.entity.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
*/
@SpringBootApplication
@Import({User.class, DBHelper.class})
public class Springboot01Application {
public static void main(String[] args) {
//获取组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
DBHelper bean1 = run.getBean(DBHelper.class);
System.out.println(bean1);
}
}
结果:如下如图所示控制台输出了我们导入的组件,user01是用@Configuration+@Bean导入的,User,DBhelper是使用@Import导入的,默认组件的名字就是全类名。
@Conditional注解:意为条件装配,它是一个根注解当满足Conditional指定的条件,则进行组件注入。
使用注解@ConditionalOnBean 意为如果容器中有指定的条件或组件成立就干什么。
**演示1:**不使用@ConditionalOnBean让Pet组件不注入容器,User组件注入容器。
package com.tain.config;
import com.tain.entity.Pet;
import com.tain.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
@Bean
public User user01(){
User fangbingbing=new User("fangbingbing",30);
fangbingbing.setPet(dog());
return fangbingbing;
}
//@Bean
public Pet dog(){
return new Pet("hashiqi");
}
}
测试:
//获取用户组件
boolean user01 = run.containsBean("user01");
System.out.println("用户组件"+user01);
//获取宠物组件 true 为容器中存在该组件 false 为容器中不存在改组件
boolean dog = run.containsBean("dog");
System.out.println("宠物组件"+dog);
结果:
**演示2:**使用@ConditionalOnBean,因为User组件依赖于Pet组件,当Pet组件不存在时,User组件也不要注入容器。
package com.tain.config;
import com.tain.entity.Pet;
import com.tain.entity.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = true )
public class MyConfig {
@Bean
@ConditionalOnBean(name = "dog")
public User user01(){
User fangbingbing=new User("fangbingbing",30);
fangbingbing.setPet(dog());
return fangbingbing;
}
//@Bean
public Pet dog(){
return new Pet("hashiqi");
}
}
//获取用户组件
boolean user01 = run.containsBean("user01");
System.out.println("用户组件"+user01);
//获取宠物组件 true 为容器中存在该组件 false 为容器中不存在改组件
boolean dog = run.containsBean("dog");
System.out.println("宠物组件"+dog);
结果:
总结:通过对比我们知道了条件装配注解的使用,springboot底层大量的使用了该注解。本次测试将该注解标记到了方法上,当然也可以使用到类上。
@ImportResource注解原生配置文件引入,及资源的导入。
使用场景:将spring原有的配置的资源与指定的配置类绑定。
测试:
已经配置好的组件信息:
<?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.tain.entity.User">
<property name="age" value="18"></property>
<property name="name" value="fanbingbing"></property>
</bean>
<bean id="hehe" class="com.tain.entity.Pet">
<property name="name" value="hashiqi"></property>
</bean>
</beans>
通过@ImportResource(“classpath:bean.xml”)注解导入配置好的组件
package com.tain.config;
import com.tain.entity.Pet;
import com.tain.entity.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @author admin
* @Configuration 告诉spring boot这是一个配置类等同于 bean.xml
* @Bean 给容器中添加组件 以方法名作为组件的id 返回的类型就是组件的类型 返回的值就是组件在容器中的实例
*/
@Configuration(proxyBeanMethods = true )
@ImportResource("classpath:bean.xml")
public class MyConfig {
@Bean
@ConditionalOnBean(name = "dog")
public User user01(){
User fangbingbing=new User("fangbingbing",30);
fangbingbing.setPet(dog());
return fangbingbing;
}
//@Bean
public Pet dog(){
return new Pet("hashiqi");
}
}
获取容器中的组件信息
boolean haha = run.containsBean("haha");
System.out.println("haha组件:"+haha);
boolean hehe = run.containsBean("hehe");
System.out.println("hehe组件:"+hehe);
测试结果:
总结:通过上述的测试我们可以将配置好的容器信息导入到指定的配置类容器。
2、配置绑定
如何使用Java读取到properties文件中的内容,并且把它封装到实体类中,以供随时使用。
- @ConfigurationProperties+@Component:注解:将配置信息绑定到Javabean中;
方式1:
- 配置
car.carName=BC
car.money=100000
- 绑定的实体类对象
package com.tain.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author admin
* 只有在spring boot容器中的组件才能使用这个功能
*/
@Component
@ConfigurationProperties(prefix = "car")
public class Car {
private String CarName;
private double money;
public Car() {
}
public Car(String carName, double money) {
CarName = carName;
this.money = money;
}
public String getCarName() {
return CarName;
}
public void setCarName(String carName) {
CarName = carName;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Car{" +
"CarName='" + CarName + '\'' +
", money=" + money +
'}';
}
}
- 测时是否绑定成功
package com.tain.controller;
import com.tain.entity.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
*/
@RestController
@RequestMapping("/hello")
public class SpringbootController {
@Autowired
Car car;
@GetMapping("/car")
public Car getCar(){
return car;
}
}
结果:
方式2:
使用@EnableConfigurationProperties + @ConfigurationProperties完成配置绑定。该方式适用于绑定第三方组件。
配置:
car.carName=BC
car.money=100000
绑定的Javabean
package com.tain.entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author admin
* 只有在spring boot容器中的组件才能使用这个功能
*/
@ConfigurationProperties(prefix = "car")
public class Car {
private String CarName;
private double money;
public Car() {
}
public Car(String carName, double money) {
CarName = carName;
this.money = money;
}
public String getCarName() {
return CarName;
}
public void setCarName(String carName) {
CarName = carName;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Car{" +
"CarName='" + CarName + '\'' +
", money=" + money +
'}';
}
}
注入到spring容器中
package com.tain.config;
import com.tain.entity.Car;
import com.tain.entity.Pet;
import com.tain.entity.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration(proxyBeanMethods = true )
@ImportResource("classpath:bean.xml")
@EnableConfigurationProperties(Car.class)
public class MyConfig {
@Bean
@ConditionalOnBean(name = "dog")
public User user01(){
User fangbingbing=new User("fangbingbing",30);
fangbingbing.setPet(dog());
return fangbingbing;
}
//@Bean
public Pet dog(){
return new Pet("hashiqi");
}
}
测试:
package com.tain.controller;
import com.tain.entity.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
*/
@RestController
@RequestMapping("/hello")
public class SpringbootController {
@Autowired
Car car;
@GetMapping("/car")
public Car getCar(){
return car;
}
}
测试结果:
方式3:@PropertySource(“classpath:application.properties”)+@Value注解读取配置.
文件名:application.properties
car.carName=BC
car.money=100000
读取配置:
package com.tain.controller;
import com.tain.entity.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
*/
@RestController
@RequestMapping("/hello")
@PropertySource("classpath:application.properties")
public class SpringbootController {
@Value("${car.carName}")
private String CarName;
@Value("${car.money}")
private double money;
@GetMapping("/car")
public String getCar(){
return "name:"+CarName+money;
}
}
结果:
总结:如果配置文件是yml文件直接用@Value读取即可
2、自动配置原理入门
(1)引导加载自动配置类
底层注解的层级结构
- @SpringBootApplication
- @SpringBootConfiguration
- @Configuration
- @Component
- @EnableAutoConfiguration
- @AutoConfigurationPackage
- @Import
- @Import
- @ComponentScan
- @Repeatable
我们开发任何一个Spring Boot项目,都会用到如下的启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
从上面代码不难看出,注解 “@SpringBootApplication”和类定义“SpringApplication.run"是最为核心的,所以要了解SpringBoot的基本原理,我们要从这两个地方入手。
1、@SpringBootApplication的分析
其实@SpringBootApplication标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用,进入这个注解可以看到下面还有很多其他注解!
@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 {
....
}
从上面代码不难看出以下4个注解是进行了原信息的标注。
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
但实际上最重核心的只有3个注解:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
所以,@SpringBootApplication等同于上述3个注解的作用也可以如下使用。
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
由于每次写这3个比较累,所以写一个@SpringBootApplication方便点。接下来分别介绍这3个注解。
- @SpringBootConfiguration注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
从上述代码可以看出@SpringBootConfiguration注解中是@Configuration,@Configuration本身其实也是一个IoC容器的配置类,任何一个标注了@Configuration的Java类定义都是一个JavaConfig配置类。提到@Configuration就要提到他的搭档@Bean。使用这两个注解就可以创建一个简单的spring配置类,可以用来替代相应的xml配置文件。
<beans>
<bean id = "car" class="com.test.Car">
<property name="wheel" ref = "wheel"></property>
</bean>
<bean id = "wheel" class="com.test.Wheel"></bean>
</beans>
相当于:
@Configuration
public class Conf {
@Bean
public Car car() {
Car car = new Car();
car.setWheel(wheel());
return car;
}
@Bean
public Wheel wheel() {
return new Wheel();
}
}
- @ComponentScan
@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
我们可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。
注:所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。
@EnableAutoConfiguration
@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 {};
}
@EnableAutoConfiguration这个注解最为重要,所以放在最后来解读,大家是否还记得Spring框架提供的各种名字为@Enable开头的注解定义?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其实一脉相承,简单概括一下就是,借助@Import的支持,收集和注册特定场景相关的bean定义。
@AutoConfigurationPackage将指定的一个包下的所有组件导入进来
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
从上述代码也可以看出该注解也是一个合成注解,@Import我们前面有介绍就是向容器中导入组件。在这里我们可以看到它给容器中导入的是一个Registrar组件,我们进入这个组件会发现里面定义了两个方法。AutoConfigurationPackage 借助Registrar给容器中导入一系列组件,将指定的一个包下的所有组件导入进来。
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
我们可以通过断点进行进行分析:
通过上述断点可以看出注解的元数据,是标记在com.tain.Springboot01Application
它拿到这些注解的元数据信息后获取所有的包名把它们批量放到一个数组中然后注册到容器中,也就是把元注解标注的包下的所有组件注册到容器中来。从断点可以看出是Springboot01Application包下的所用组件。
@Import({AutoConfigurationImportSelector.class}) 该注解向容器中导入了组件AutoConfigurationImportSelector,下面我们对该组件进行分析。
进入组件我们可以看到这个方法,利用该方法中的getAutoConfigurationEntry(annotationMetadata)给容器中批量导入一些组件
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
利用断点对该方法进行分析看看到底导入了那些组件。
通过断点我们发现是调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
利用工厂加载private static Map<String, List> loadSpringFactories(ClassLoader classLoader)得到了所有的组件。
SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoader == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
利用断点进行分析得到,所有要加载的类都来源于META-INF/spring.factories位置的一个加载文件。默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件,自动加载的类都位于spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面的有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/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.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个场景的所有自动配置启动的时候默认全部加载xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。当你引入依赖对印的配置类会生效。
修改默认配置
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
给容器中加入了文件上传解析器;
总结:
• SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
• 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
• 生效的配置类就会给容器中装配很多组件
• 只要容器中有这些组件,相当于这些功能就有了
• 定制化配置
• 用户直接自己@Bean替换底层的组件
• 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties