关联博文:
SpringBoot自动配置原理解析(一)
SpringBoot自动配置原理解析(二)
SpringBoot自动配置原理解析(三)
SpringBoot自动配置原理解析(四)
SpringBoot自动配置原理解析(五)
继SpringBoot自动配置原理解析(一)后,我们继续分析SpringBoot如何进行自动配置的。
前面我们从表现上跟踪了一下SpringBoot自动配置的大概过程,但是并没有说明处理器、环节等信息,本文从源码角度我们看一下。
首先说明一下,BeanDefinition的扫描注册发生在refresh过程中的invokeBeanFactoryPostProcessors
方法中,具体处理器是ConfigurationClassPostProcessor
,bean实例化则是发生在refresh方法中的finishBeanFactoryInitialization
环节。
在Spring中refresh分析之invokeBeanFactoryPostProcessors方法详解一文中我们简要分析了PostProcessorRegistrationDelegate
的invokeBeanFactoryPostProcessors
方法。其对AbstractApplicationContext的成员beanFactoryPostProcessors
处理完后,就会从BeanFactory
这个容器中找寻BeanDefinitionRegistryPostProcessor
,并优先对那些实现了PriorityOrdered
接口的类遍历挨个触发其postProcessBeanDefinitionRegistry
方法。
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
本文这里从容器BeanFactory中得到的(注意哦,不是从ApplicationContext的成员中得到)同时实现接口BeanDefinitionRegistryPostProcessor&PriorityOrdered
,只有后置处理器ConfigurationClassPostProcessor
。其是在AnnotationConfigUtils
的registerAnnotationConfigProcessors
方法中被注册到BeanFactory中的。
【1】ConfigurationClassPostProcessor
如下图所示,其首先判断当前BeanDefinitionRegistry
(本文这里是指DefaultListableBeanFactory
)是否触发过ConfigurationClassPostProcessor
,如果触发过则抛出异常,否则触发processConfigBeanDefinitions
方法。
processConfigBeanDefinitions方法源码
// ConfigurationClassPostProcessor
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 候选配置类名称,首先从registry获取 这里registry是DefaultListableBeanFactory
String[] candidateNames = registry.getBeanDefinitionNames();
// 遍历循环,判断其是否作为一个configuration 类被处理过,如果没有则放入configCandidates
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
//如果为空则直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
//根据@Order排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
// 尝试获取自定义的internalConfigurationBeanNameGenerator
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
// 本文这里获取的为null
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
// 如果环境为null,实例化一个环境
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// Parse each @Configuration class
// 实例化ConfigurationClassParser ,这个玩意将会用来解析配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
//候选配置类--当前要被解析的配置类
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 已经执行过parse的
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
// 注意,这里是do while循环 这个方法执行之后就拥有了当前应用的所有配置类
do {
// 解析配置类,
parser.parse(candidates);
// 校验类是否为final,beanMethod是否覆盖
parser.validate();
// 获取当前解析器拥有的配置类,移除掉已经解析过的
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
//第一次没有意义,后续循环有意义
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 实例化一个reader然后加载配置类涉及到的BeanDefinition,这个很重要!
this.reader.loadBeanDefinitions(configClasses);
//放入已解析集合
alreadyParsed.addAll(configClasses);
//清空candidates
candidates.clear();
// 判断registry中的BeanDefinition数量与candidateNames是否一致
// 如果不一致就检索哪些新引入且未解析的候选配置类放到candidates中
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
//找到oldCandidateNames不包含且属于候选配置类,且未被解析的
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
// 如果candidates不为空,则再次循环解析
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
//注册单例bean ImportRegistry
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
// 清空缓存
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
① 遍历循环检测是否为候选配置类
原始的candidateNames
也就是registry.getBeanDefinitionNames()
获取的如下所示:
// ConfigurationClassPostProcessor
0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
// AutowiredAnnotationBeanPostProcessor
1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
// CommonAnnotationBeanPostProcessor
2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
// EventListenerMethodProcessor
3 = "org.springframework.context.event.internalEventListenerProcessor"
// DefaultEventListenerFactory
4 = "org.springframework.context.event.internalEventListenerFactory"
5 = "recommendApplication"
// SharedMetadataReaderFactoryContextInitializer$SharedMetadataReaderFactoryBean
6 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"
然后会从上面得到的candidateNames进行遍历循环,判断其是否作为一个configuration 类被处理过,如果没有则放入configCandidates 。
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
如何判断呢?如下几种情况直接排除:
- 有FactoryMethodName;
- BeanFactoryPostProcessor、BeanPostProcessor、AopInfrastructureBean、EventListenerFactory类型均不行;
- 其是一个接口
- 没有@Configuration注解标注也没有@Component、@ComponentScan、@Import、@ImportResource标注;
- 没有包含@Bean标注的方法。
本文这里第一次遍历筛选后只剩下主启动类RecommendApplication。
② 解析配置类
首先实例化ConfigurationClassParser
,然后对前面筛选后的候选配置类进行解析。如下图所示,这里会触发ConfigurationClassParser
的parse方法。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 本文从这里进入
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
// 这个方法也很重要 !!! 从spring.factories中检索配置类就是在这里触发的
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
// 这里为当前需要解析的beanName实例化了一个ConfigurationClasss实例交给下游
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 判断是否可以跳过
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// Map<ConfigurationClass, ConfigurationClass> configurationClasses
//这里判断配置类是否已经存在,如果存在则合并或者替换
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
//递归处理配置类及其父类,这里会根据configClass获取到SourceClass
SourceClass sourceClass = asSourceClass(configClass);
do {
// 核心解析方法
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
// 放入configurationClasses这个LinkedHashMap中 ,后面会使用
this.configurationClasses.put(configClass, configClass);
}
这里doProcessConfigurationClass
方法是真正解析配置的方法,是本文讲述的核心的方法。
【2】核心方法doProcessConfigurationClass
这个方法将会解析当前配置类对应的SourceClass 那些注解、导入以及@Bean Method。
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 如果标注了@Component注解,则首先尝试处理成员类(内部类)
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
// 解析@PropertySource注解,将会添加配置信息到环境中
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
// 解析@ComponentScan注解,使用ComponentScanAnnotationParser解析器
// 扫描@Configuration、@Service、@Controller、@Repository和@Component注解并注册BeanDefinition
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
//获取扫描解析到的BeanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
// 对scannedBeanDefinitions遍历,检测是否为候选配置类,触发parse
//也就是对扫描到的类再次触发解析过程,递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
// 解析@Import注解,然后进行实例化,并执行ImportBeanDefinitionRegistrar的
//registerBeanDefinitions逻辑,或者ImportSelector的selectImports逻辑 或者再次触发解析
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
// 解析@ImportResource注解,并加载相关配置信息
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// Process individual @Bean methods
//解析标注了@Bean注解的方法并注册到configclass中Set<BeanMethod> beanMethods里
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
// 解析其实现接口中标注了@Bean注解的方法并注册到configclass中Set<BeanMethod> beanMethods里
processInterfaces(configClass, sourceClass);
// Process superclass, if any
// 尝试处理其父类
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}
核心流程梳理如下:
- 如果标注了@Component注解,则首先尝试处理成员类(内部类)
- 解析@PropertySource注解,将会添加配置信息到环境中
- 解析@ComponentScan注解,使用ComponentScanAnnotationParser解析器扫描@Configuration(复合注解标注了@Component)、@Service、@Controller、@Repository和@Component注解并注册BeanDefinition
- 解析@Import注解,然后进行实例化,并执行ImportBeanDefinitionRegistrar的registerBeanDefinitions逻辑,或者ImportSelector的selectImports逻辑,或者再次触发配置类解析方法processConfigurationClass
- 解析@ImportResource注解,并加载相关配置信息
- 解析标注了@Bean注解的方法并注册到
configclass的Set<BeanMethod> beanMethods
里 - 解析其实现接口中标注了@Bean注解的方法并注册到configclass中
Set<BeanMethod> beanMethods
里
① 处理导入processImports
这个方法是用来处理导入的类的,分为三个分支:
- 如果导入类是ImportSelectorl类型,则进行实例化:
- 如果是
DeferredImportSelector
,则触发其handle方法,我们@EnableAutoConfiguration
注解引入的AutoConfigurationImportSelector
就是DeferredImportSelector类型。 - 否则触发其selectImports方法,递归调用processImports
- 如果是
ImportBeanDefinitionRegistrar
如果是该类型,实例化后添加到当前configClass的成员importBeanDefinitionRegistrars
中。AutoConfigurationPackages.Registrar
就被这样处理了- 放入importStack,作为配置类触发
processConfigurationClass
方法再次进行解析
// ConfigurationClassParser
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
// 如果导入候选为空,直接返回
if (importCandidates.isEmpty()) {
return;
}
// 检测是否循环导入
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
// 放入当前configClass
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 判断是否为ImportSelector类型
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
//触发selector的selectImports方法,得到importSourceClasses ,递归调用processImports
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if
// 判断是否为ImportBeanDefinitionRegistrar类型
(candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
// 作为 @Configuration class进行处理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
//candidate作为配置类再次触发解析,importedBy 中将放入configClass
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
//...两个异常
finally {
// 从importStack移除顶层结点
this.importStack.pop();
}
}
}
这里我们要特别注意processConfigurationClass(candidate.asConfigClass(configClass));
这行代码。首先这里candidate.asConfigClass(configClass)
也就是导入的候选类作为配置类,这里会得到一个新的配置类ConfigurationClass 实例并向其成员集合importedBy中添加configClass表明其是被configClass导入的。然后再次触发配置类解析过程。
public ConfigurationClass asConfigClass(ConfigurationClass importedBy) {
if (this.source instanceof Class) {
return new ConfigurationClass((Class<?>) this.source, importedBy);
}
return new ConfigurationClass((MetadataReader) this.source, importedBy);
}
//像成员importedBy添加ConfigurationClass importedBy
public ConfigurationClass(MetadataReader metadataReader, @Nullable ConfigurationClass importedBy) {
this.metadata = metadataReader.getAnnotationMetadata();
this.resource = metadataReader.getResource();
this.importedBy.add(importedBy);
}
为什么这里我们特别强调了importedBy这个LinkedHashSet呢?因为 在后面使用ConfigurationClassBeanDefinitionReader
加载BeanDefinition
时,importedBy不为空的配置类会被注册BeanDefinition到BeanFactory中。
② processImports过程中,我们的AutoConfigurationImportSelector做了什么?
如下所示,在processImports过程中如果当前selector 是DeferredImportSelector实例的话,那么将会触发下面这个方法。
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
我们看下其handle方法,这里的逻辑是首先实例化DeferredImportSelectorHolder
,然后将holder 放到this.deferredImportSelectors
这个ArrayList中并没有触发if逻辑走的是else分支。
public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
configClass, importSelector);
// this.deferredImportSelectors默认是new ArrayList<>() 这里直接触发的是else逻辑
if (this.deferredImportSelectors == null) {
//如果为null,则实例化handler 将holder注册然后触发processGroupImports
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
handler.register(holder);
handler.processGroupImports();
}
else {
//将DeferredImportSelectorHolder 放入集合
this.deferredImportSelectors.add(holder);
}
}
截止到目前我们还没有看到META-INF\spring.factories
中配置的自动配置类加载与过滤,这个过程发生在this.deferredImportSelectorHandler.process();
这个方法里面!接下来我们将会分析该方法。
这里可以先说明一下,parser.parse(candidates);
方法执行后,ConfigurationClassParser的成员Map<ConfigurationClass, ConfigurationClass> configurationClasses
就拥有了所有应该出现
的配置类。
什么叫应该出现的呢?比如我们的@Controller、@Service、@Component、@Configuration以及哪些由于递归引入的配置类。需要注意的是
META-INF\spring.factories
中配置的自动配置类不会完全引入,将会根据当前应用具体情况相应引入。比如本文环境下没有引入RedisAutoConfiguration,但是存在DataSourceAutoConfiguration。