SpringBoot 原理
起步依赖:Maven的依赖传递原理,当引入某个依赖后,如果该依赖依赖了其他依赖,那么其他依赖也会被引入进来
自动配置:SpringBoot的自动配置就是当spring容器启动后,一些配置类、bean对象就自动存入到了IOC容器中,不需要我们手动去声明,从而简化了开发,省去了繁琐的配置操作
在启动类上方加如下注解实现自动配置
方案一:@ComponentScan 组件扫描 使用繁琐、性能低
java@ComponentScan({"com.example","com.itheima"})方案二:@Import 导入,使用@Import导入的类会被Spring加载到 IOC 容器中,导入形式主要有以下几种:
导入 普通类
java@Import({TokenParser.class})导入 配置类 会将配置类中的 @Bean 的对象全部导入
java@Import({HeaderConfig.class})导入 ImportSelector 接口实现类,该实现类会实现接口的selectImports方法,将需要导入的Bean以字符串数组的形式返回
java@Import({MyImportSelector.class})javapublic class MyImportSelector implements ImportSelector { public String[] selectImports(AnnotationMetadata importingClassMetadata) { return new String[]{"com.example.HeaderConfig"}; } }
方案三:@EnableXxxx 注解,封装了 @Import 注解,Import 什么 bean ,由第三方依赖提供方决定,我们只需要加上该@EnableXxxx 注解即可
@Conditional 注解
作用:按照一定的条件进行判断,在满足给定条件后才会注册相应的bean对象到Spring IOC容器中
位置 :方法、类
@Conditional 本身是一个父注解,派生出大量的子注解:
- @ConditionalOnClass:判断环境中是否有指定的字节码文件,才注册bean到 IOC 容器,即引入指定的jar包才会注册
- @ConditionalOnMissingBean:判断环境中有无对应的bean(类型 或 名称),才注册 bean 到 IOC 容器
- @ConditionalOnProperty:判断配置文件中有无对应的属性和值,才注册 bean 到 IOC 容器

自动配置源码跟踪
对 @SpringBootApplication 注解的源码查看,发现有该注解上有以下注解
java@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })- @SpringBootConfiguration ,该注解与@Configuration注解作用相同,用来声明当前也是个配置类
- @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包
- @EnableAutoConfiguration:SpringBoot实现自动化配置的核心注解
所以对 @EnableAutoConfiguration 进行源码跟踪,发现其使用了@Import注解,会导入该类中实现ImportSelector接口的 selectImports方法返回的字符串中的所有类
java@Import(AutoConfigurationImportSelector.class)查看该AutoConfigurationImportSelector类如何实现的 selectImports 方法
java@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }重点关注该方法返回值的内容,追踪 getAutoConfigurationEntry 方法,查看注释和源码,大概了解到 configuration 变量包括了需要导入的类,exclusions包括了需要排除的类
java/** * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata} * of the importing {@link Configuration @Configuration} class. * @param annotationMetadata the annotation metadata of the configuration class * @return the auto-configurations that should be imported */ 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); }我们再查看获得 configuration 的方法 getCandidateConfigurations,其中有个断言式 Assert ,提到配置类在 META-INF/spring.factories 和 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 两个文件中,
spring.factories 是旧版本的配置文件,在SpringBoot 3.x 版本移除,使用后者配置文件
java/** * Return the auto-configuration class names that should be considered. By default * this method will load candidates using {@link ImportCandidates} with * {@link #getSpringFactoriesLoaderFactoryClass()}. For backward compatible reasons it * will also consider {@link SpringFactoriesLoader} with * {@link #getSpringFactoriesLoaderFactoryClass()}. * @param metadata the source metadata * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation * attributes} * @return a list of candidate configurations */ protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = new ArrayList<>( SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
我们看一眼提到的两个文件

发现该文件下都是以 AutoConfiguration 结尾的,其实这些都是配置类,我们可以查看其中一个配置类

如 CacheAutoConfiguration 类, 点进去 @AutoConfiguration 注解,发现其被 @Configuration 注解修饰,该类是配置类,所以导入时,会将其所有的 @Bean 导入,这就解释了整个 SpringBoot 自动配置的流程
@AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}
@Bean
public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
ObjectProvider<CacheManager> cacheManager) {
return new CacheManagerValidator(cacheProperties, cacheManager);
} 总结一下,SpringBoot自动配置的原理,大致是通过 @SpringBootApplication 注解的 @EnableAutoConfiguraion 注解,该注解被@Import注解修饰,@Import注解的参数为一个实现了 ImportSelector 接口的类,通过其重写的 selectImports 方法,规定导入那些配置类,通过 @Conditional 注解进行条件匹配,从而这些配置类的所有满足条件的 @Bean 都会被 IOC 接管,我们在程序中也可以直接注入了。顺带一提,这些配置类是从依赖的Spring jar包的两个文件中写好的,以下为流程图
