SpringBoot自动装配实现原理
首先我们要知道Spring Boot自动装配的核心注解是@SpringBootApplication,该注解是spring boot的启动类注解,它是一个复合注解,里面包含
1.@SpringBootConfiguration:
该注解上有一个 @Configuration注解,表示这个spring boot启动类是一个配置类,最终要被注入到spring容器中。
2.@EnableAutoConfiguration
表示开启自动配置,它也是一个复合注解,里面包含
a:@AutoConfigurationPackage:该注解上有一个@Import(AutoConfigurationPackages.Registrar.class)注解,
其中 Registrar 类的作用是将启动类所在包下的所有子包的组件扫描注入到spring容器中。
b:@Import(AutoConfigurationImportSelector.class):其中AutoConfigurationImportSelector类中有一个getCandidateConfigurations()方法,
该方法通过SpringFactoriesLoader.loadFactoryNames()方法查找位于META-INF/spring.factories文件中的所有自动配置类,并加载这些类。
所以spring boot在整个的启动过程中,其实就是在类路径的META-INF/spring.factories 文件中找到EnableAutoConfiguration对应的所有的自动配置类,然后将所有自动配置类加载到spring容器中。
我们来看一下流程图
下面我们附上源码
1.@SpringBootApplication中的@EnableAutoConfiguration表示开启自动装配
2.@Import({AutoConfigurationImportSelector.class}) 该注解表示导入该 AutoConfigurationImportSelector类
3.AutoConfigurationImportSelector类下会有一个AutoConfigurationGroup内部类
该内部类下的process方法会先被执行
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
//保存到autoConfigurationEntries 这个list中
this.autoConfigurationEntries.add(autoConfigurationEntry);
//把配置类包装成一个map返回
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
4.然后调用getAutoConfigurationEntry方法
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
//删除需要排除的类
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
//包装成AutoConfigurationEntry类
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
5.这个方法会获取SpringBootApplication中的exclude、excludeName排除的类
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
String name = this.getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> {
return "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?";
});
return attributes;
}
6.通过spi机制 获取META-INFO下的spring.factoryies中@EnableAutoConfiguration注解
为key的value值,总共有129个
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;
}
7.删除重复的
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList(new LinkedHashSet(list));
}
8.获取到需要排除的类
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet();
excluded.addAll(this.asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(this.getExcludeAutoConfigurationsProperty());
return excluded;
}
9.保存到autoConfigurationEntries 这个list中
10.把配置类包装成一个map返回
注:9、10请参照第3步中的源码