日常使用springboot时spring会按照默认的约定自动注入一些常用的bean。这些bean的beanDefinition信息在refresh()
方法的invokeBeanFactoryPostProcessors(beanFactory)
这一步被注入。在对beanFactory进行后置处理时,会依次调BeanFactoryPostProcessor,其中ConfigurationClassPostProcessor
用来处理配置类,处理过程中通过org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry()
方法获取自动配置的类信息
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);
}
getAutoConfigurationEntry()
中获取自动配置信息的主要方法是getCandidateConfigurations()
,用于获取候选的自动配置类
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;
}
getCandidateConfigurations()
中通过ImportCandidates.load
方法加载自动配置类的信息。
不过在当前方法中,springboot没有根据传入的参数metadata加载自动配置类,而是固定的向load方法传入AutoConfiguration.class
参数,默认加载AutoConfiguration对应的配置文件
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
Assert.notNull(annotation, "'annotation' must not be null");
ClassLoader classLoaderToUse = decideClassloader(classLoader);
String location = String.format(LOCATION, annotation.getName());
Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
List<String> autoConfigurations = new ArrayList<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
autoConfigurations.addAll(readAutoConfigurations(url));
}
return new ImportCandidates(autoConfigurations);
}
在load()
方法中,根据传入的注解反射对象(AutoConfiguration.class
)和静态常量LOCATION
("META-INF/spring/%s.imports"
)解析出要加载的配置文件路径META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
根据路径找到文件,可以看到里面有候选的自动配置类的全限定类名。
springboot会逐行读取这个文件,将信息包装成一个ImportCandidates
类型的对象,再将对象中的信息添加到一个List<String>类型的集合中,就获得了候选的自动配置类的全限定类名集合。
springboot会根据这些自动配置类中配置的信息自动注入bean,当然springboot不会全部注入,在获取到这些配置类信息后,还要经过去重、排除、过滤等操作,才能决定最终需要注入的bean。