面试官:谈谈你对Springboot自动装配的了解叭
回答:
它是starter的基础,也是Spring Boot 的核心,可以简单概括为:通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。
(1)SpringBoot核心注解SpringBootApplication是由几个注解组成的,其中比较重要的一个EnableAutoConfiguration注解
(2)引导类上开启@EnableAutoConfiguration,其内部通过@import注解引入ImportSelector方法
(3)查找工程jar包中META-INF/spring.factories文件
(4)装载内部的对象到容器
在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下里面的源代码:
- 这里面包含了:
- @SpringBootConfiguration
- 我们点进去通过源码得知他是一个@Configuration,所以也就是对spring原生注解的封装
- @EnableAutoConfiguration
- @ComponentScan
- 默认扫描的是与该类同级的类或者同级包下的所有类,是spring的原生注解之一
@EnableAutoConfiguration(重头戏——自动装配核心)
- 一旦加上此注解,那么将会开启自动装配功能,容易点讲,Spring会试图在自己的classpath(类路径)下找到所有配置的Bean然后进行装配。
- 装配Bean时,会根据若干个(Conditional)定制规则来进行初始化。我们看一下它的源码:
- 导入了自动装配类,AutoConfigurationImportSelector.class
- AutoConfigurationImportSelector实现了DeferredImportSelector,而DeferredImportSelector实现了ImportSelector接口( 该接口主要是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理过后才会执行
- 回过头来我们看一下AutoConfigurationImportSelector的自动配备核心方法 selectImport
-
//自动装配的方法 public String[] selectImports(AnnotationMetadata annotationMetadata) { //判断是否自动装配 if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } } protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { //获取所有元数据信息 AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //获取所有加载bean的条件配置 List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); //过滤并删除掉重复的bean configurations = this.removeDuplicates(configurations); Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = this.filter(configurations, autoConfigurationMetadata); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
- 该方法刚开始会先判断是否进行自动装配,而后会从META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性,紧接着会调用getCandidateConfigurations方法:
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;
}
- 在这里又遇到我们的老熟人了–SpringFactoryiesLoader, 它会读取META-INF/spring.factories下的EnableAutoConfiguration的配置,紧接着在进行排除与过滤,进而得到需要装配的类。最后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件,代码如下:
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = this.getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
Iterator var5 = listeners.iterator();
while(var5.hasNext()) {
AutoConfigurationImportListener listener = (AutoConfigurationImportListener)var5.next();
this.invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类.