SpringBoot自动配置原理
在了解SpringBoot自动配置原理前,我们得先了解SpringBoot的启动类注解@SpringBootApplication,该注解是一个复合注解。
点进去可以发现,其本身依赖了很多注解,而SpringBoot自动配置的关键性注解是@EnableAutoConfiguration,但其实这个注解也是一个复合注解,用于载入所有应用程序需要导入的默认配置。当然,@SpringBootConfiguration和@ComponentScan也是自动配置中比较重要的注解。
- @SpringBootConfiguration:底层是@Configuration,也就是说其本身是支持JavaConfig的方式进行配置,可以理解为Configuration配置类等同于XML文件。
- @ComponentScan:扫描注解,说成事务大家也好理解,主要用来扫描当前类下的package,也就是将@Controller、@Service、@Component、@Repository等标记的加载到IOC容器中。
点进来就可以看到SpringBoot自动配置最重要的两个注解:
- @AutoConfigurationPackage:自动配置包
- @Import(AutoConfigurationImportSelector.class)
EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY是什么?这里我们可以先猜测成一个资源配置文件。
一、@AutoConfigurationPackage
这个知道它是自动配置包就行,点进去我们可以发现,它本身还是依赖于@Import,点进AutoConfigurationPackages.Registrar.class我们可以发现,其内部是重写了registerBeanDefinitions(…)方法,并调用了register方法来注册Bean。
了解:register(…)方法中,在注册bean时,先对bean进行查找,registry.containsBeanDefinition(BEAN)返回的是一个boolean值,如果为true时,就说明bean已经存在,在注册时需要添加索引;如果为false,bean就不存在,这是我们就可以注册一个bean。
二、@Import(AutoConfigurationImportSelector.class)
这个注解可以说才是真正的SpringBoot自动配置的核心奥义。首先我们点进去看一下源码,看不懂英文的话也没什么,可以百度翻译,但一些关键词还是得懂的,像什么Auto、Configuration啥的,回到源码我们可以看到AutoConfigurationImportSelector类实现DeferredImportSelector接口
然后我们可以点进该接口看一下,这个接口又继承ImportSelector类,
点进这个类我们可以发现,其调用了selectImports()方法,也就是实现自动配置的一个核心方法。
我们可以看到它里边调用了一个叫isEnabled()的方法,isEnabled()方法用来判断SpringBoot是否开启了自动配置。若开启就通过getAutoConfigurationEntry()来获取需要配置的Bean全限定名数组,否则就直接返回空数组。
getAutoConfigurationEntry()方法,用来获取需要自动配置的bean信息。
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取@EnableAutoConfiguration注解的属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 从spring.factories文件中获取配置类的全限定名数组
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重
configurations = removeDuplicates(configurations);
// 获取注解中exclude或excludeName排除的类集合
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查被排除类是否可以实例化,是否被自动配置所使用,否则抛出异常
checkExcludedClasses(configurations, exclusions);
// 去除被排除的类
configurations.removeAll(exclusions);
// 使用spring.factories配置文件中配置的过滤器对自动配置类进行过滤
configurations = getConfigurationClassFilter().filter(configurations);
// 抛出事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getAttributes():获取@EnableAutoConfiguration注解属性
getCandidateConfigurations():从spring.factories文件获取需要配置的bean。
getCandidateConfigurations()方法通过SpringFactoriesLoader的loadFactoryNames()方法从所有的spring.factories文件中获取需要配置的bean全限定名列表。
打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在。
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了@Configuration的JavaConfig形式的IOC容器配置类 ,然后将这些都汇总成为一个实例并加载到IOC容器中。
注意:SpringBoot 2.X和SpringBoot 3.X自动装配是有区别的
springboot2.x和springboot3.x的版本的约定位置是不一致的。
在SpringBoot 2.X中:
约定配置是META-INF下面的的spring.factories 文件中
在SpringBoot 3.X中:
约定配置是META-INF下面的spring文件夹下的org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中
最后我们可以启动类时debug一下。找到beanFactory,然后找到下面这个