一 . 前言
无意中把 自动装配的相关源码补齐了, 所以终于能开启这个系列了.
这个系列我们来过一下自动装配的流程 , 整个流程从一年前就开始学习 , 一直没有找到合适的表达形式 , 最近灵感迸发 , 正好试试这个方式.
二 . 背景知识点
2.1 基础背景
Spring Boot 自动配置尝试根据添加的 jar 依赖项自动配置 Spring 应用程序 , Spring 是允许对自动装配进行替代 , 使Spring 的使用更灵活.
当然 , 配置是不可能平白无故产生 , 打开 Spring-boot-autoconfiture 包就可以看到对应的几个配置文件 :
- spring.factories : 自动装配类 , Spring 启动的时候会用到 ,我们后面分析
- spring-autoconfigure-metadata.properties : 配置信息
- spring-configure-metadata.json : 配置元数据 , 业务中会通过该文件进行属性映射和处理
- 例如 : spring.jpa.hibernate.ddl-auto 提供的多种模式
{
"name": "spring.jpa.hibernate.ddl-auto",
"values": [
{
"value": "none",
"description": "Disable DDL handling."
},
{
"value": "validate",
"description": "Validate the schema, make no changes to the database."
},
{
"value": "update",
"description": "Update the schema if necessary."
},
{
"value": "create",
"description": "Create the schema and destroy previous data."
},
{
"value": "create-drop",
"description": "Create and then destroy the schema at the end of the session."
}
]
}
复制代码
自动装配和自动配置
- 自动配置:是 Spring Boot 提供的,实现通过 jar 包的依赖,能够自动配置应用程序。
- 例如说:我们引入 spring-boot-starter-web 之后,就自动引入了 Spring MVC 相关的 jar 包,从而自动配置 Spring MVC 。
- 自动装配:是 Spring 提供的 IoC 注入方式,具体看看 《Spring 教程 —— Beans 自动装配》 文档。
2.2 基础使用
我们来看一下基础的使用 :
@Configuration
@EnableAutoConfiguration
public class BeanAnnotationConfig {
@Bean
public BeanAnnotationTestService getBeanAnnotationTestService() {
return new BeanAnnotationTestService();
}
}
复制代码
实现基础 : 自动装配基于 @SpringBootApplication 注解实现
F- SpringBootApplication
|- @SpringBootConfiguration: 标记这是一个 Spring Boot 配置类
|- @EnableAutoConfiguration : 用于开启自动配置功能
|- @AutoConfigurationPackage : 获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到 Spring IOC 容器中
|- @Import : 导入资源(并且由AutoConfigurationImportSelector)
|- @ComponentScan(内部为excludeFilters )
复制代码
三. 源码分析
来尝试一种新的方式来解析源码 :
3.1 扫描的起点
3.2 业务扫描关系
我们先看下基本逻辑 :
1. 由 ConfigurationClassPostProcessor 开始
2. 在 ConfigurationClassPostProcessor 的 doProcessConfigurationClass 中获取所有的 config 类信息 , 其中就包括 @Bean 标注的Bean
3. 最终在 ConfigurationClassBeanDefinitionReader 的 loadBeanDefinitionsForBeanMethod 中进行加载
C01- ConfigurationClassPostProcessor : 处理 processConfigBeanDefinitions 类型
M101M102M102 doWhile调用do-while parse 循环 处理ConfigurationClassParser 处理ConfigurationClassBeanDefinitionReader 处理判断已处理的和生成新得未处理candidates 为空 ,处理完成将ImportRegistry注册为一个bean清除外部提供的MetadataReaderFactory中的缓存M101M102M102 doWhile
C01- ConfigurationClassPostProcessor
M101- postProcessBeanDefinitionRegistry
- System.identityHashCode(registry) 获取一个 registryId
- 将 id 加入 Set<Integer>
- processConfigBeanDefinitions(registry) : 详看 M102
M102- processConfigBeanDefinitions
- 从 BeanDefinitionRegistry 获取一个 List<BeanDefinitionHolder> 集合
?- 通过每个 BeanDefinition 的 Attribute是否为 configurationClass , 加入集合
?- 此处是将 BeanDefinitionRegistry 获取的所有类过滤后加入
- 通过 Order 进行一次排序
- 获取相关 Generator ,并且通过这些 Generator 获取一个 ConfigurationClassParser
- List 封装为一个 Set<BeanDefinitionHolder> , 保证其唯一性
FOR- 循环所有的 BeanDefinitionHolder
- 通过 ConfigurationClassParser 处理该集合
- 通过 ConfigurationClassBeanDefinitionReader load configClasses
// M01 伪代码
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
//.....
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
// M02 伪代码
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// Step 1 : 获取 configurationClass 集合
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// .... 此处做了相关判断
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
// Step 2 : 排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 省略 : 生成 ConfigurationClassParser 的必要参数
// Step 3 : 准备一个 ConfigurationClassParser
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 准备所有的 ConfigClass 的 BeanDefinitionHolder 集合
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// Step 4 : parse 处理
parser.parse(candidates);
parser.validate();
// 准备 ConfigurationClass 并且去掉已经处理的
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Step 5 : reader 处理
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
}while (!candidates.isEmpty());
// 将ImportRegistry注册为一个bean,以便支持importtaware @Configuration类
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// 清除外部提供的MetadataReaderFactory中的缓存
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
复制代码
C02- ConfigurationClassParser : 主处理逻辑
ConfigurationClassParser 主要用于解析单个配置类 . 但是因为 @Import 注解的原因 , 可能会产生多个ConfigurationClass
M101M102M202M203M204调用FOR 循环处理 SourceClass调用 processConfigurationClass调用 doProcessConfigurationClass循环处理 PropertySources循环处理 ComponentScans递归处理 @Bean method递归处理 @Import获取超类返回超类或者null递归处理超类将处理类加入 Map 集合M101M102M202M203M204
C02- ConfigurationClassParser
M201- parse(Set<BeanDefinitionHolder> configCandidates)
- 循环 Set<BeanDefinitionHolder> , 根据其不同类型调用不同的parse
- this.deferredImportSelectorHandler.process();
?- 调用内部类 DeferredImportSelectorHandler 处理相关的逻辑
M202- processImports
- this.importStack.push(configClass) :
// 从这里之后开始核心的 Class 类处理逻辑 , 会分别判断 SourceClass 的类型
FOR- Collection<SourceClass> : for 循环传入的集合 (Collection - Group.Entry.getImportClassName) , 获取 SourceClass
1- TODO
2- TODO
3- 除了以上2种外
- processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter) : M203
M203- processConfigurationClass
- asSourceClass(configClass, filter) : 获取 SourceClass
- sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter) : M204
- TODO 待完善
M204- doProcessConfigurationClass
- 如果类注解是 Component , 调用 processMemberClasses(configClass, sourceClass, filter)
- For 循环 其上 PropertySources 注解 , 并调用 processPropertySource(propertySource)
- For 循环 其上 ComponentScans 注解
- this.componentScanParser.parse 获取 Set<BeanDefinitionHolder>
FOR- Set<BeanDefinitionHolder>
1- 获取 BeanDefinition
2- 如果检查给定的bean定义是配置类的候选 , 调用 parse(bdCand.getBeanClassName(), holder.getBeanName())
?- 这里可以看成是一个递归处理
- 调用 processImports 处理 @Import 注解对应的类
?- 这其实也是一个递归处理
- 获取 ImportResource 对应的属性
IF- 如果对应属性不为空
- importResource.getStringArray("locations") : 获取其中的 locations 属性 String[]
- 获取 BeanDefinitionReader
FOR- 循环数组
- configClass.addImportedResource(resolvedResource, readerClass)
- retrieveBeanMethodMetadata(sourceClass) : 获取其中 @Bean 对应Method
FOR- 循环上面的 Set<MethodMetadata>
- configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
- processInterfaces(configClass, sourceClass) : 处理其中 interface default 方法
- 获取父类型 , 再将其添加到 Map<String, ConfigurationClass> 中
- return sourceClass.getSuperClass() : 找到超类,返回其注释元数据并递归
M05- processMemberClasses
复制代码
C03- DeferredImportSelectorHandler
C03- DeferredImportSelectorHandler
M301- process() :
- 将 List<DeferredImportSelectorHolder> 排序后注入到 DeferredImportSelectorGroupingHandler 中
- 调用 handler.processGroupImports() 处理 所有的 Group
复制代码
C04- DeferredImportSelectorGroupingHandler
M301M401M501获取所有Group 后调用 processGroupImports 处理 Group获取 Group process 处理总逻辑 中 DeferredImportSelectorHolder执行 Group process 处理总逻辑M301M401M501
C04- DeferredImportSelectorGroupingHandler
M401- processGroupImports
- 先循环 DeferredImportSelectorGrouping
- grouping.getImports() : 返回 Iterable<Group.Entry>
- 获取 Group 中 DeferredImportSelectorHolder
- DeferredImportSelector.Group 处理 (process) 每一个 DeferredImportSelectorHolder (C05 逻辑)
FOR- 其次循环每个 DeferredImportSelectorGrouping 的 Imports
- this.configurationClasses.get(entry.getMetadata()) : 获取当前 ConfigurationClass
- processImports 处理 , 详见 processImports 方法逻辑 (M202)
复制代码
C05- AutoConfigurationImportSelector
从上一步中 , 其中一个 DeferredImportSelectorHolder 就是 AutoConfigurationImportSelector
M401M501M502M503调用通过 AnnotationMetadata 获取 AutoConfigurationEntry获取所有的 configurations 列表过滤重复及filter 过滤需要跳过的ConfigClass处理 listener 和 event返回一个 AutoConfigurationEntryAutoConfigurationEntry 加入 Map<String, AnnotationMetadata>M401M501M502M503
C05- AutoConfigurationImportSelector
M502- getAutoConfigurationEntry
- getAttributes(annotationMetadata) : 获取 AnnotationMetadata 中属性
- getCandidateConfigurations(annotationMetadata, attributes) : 获取所有的 configurations 列表
- removeDuplicates : 移除重复的配置类
- checkExcludedClasses + removeAll : 移除 getExclusions(annotationMetadata, attributes) 获取的类
- getConfigurationClassFilter().filter(configurations)
- filter.match(candidates, this.autoConfigurationMetadata) : filter 过滤是否跳过
- fireAutoConfigurationImportEvents(configurations, exclusions) : 详见 fireAutoConfigurationImportEvents
- new AutoConfigurationEntry(configurations, exclusions) : 返回一个 AutoConfigurationEntry
M503- fireAutoConfigurationImportEvents
- getAutoConfigurationImportListeners() : 获取AutoConfigurationImportListener集合
- listener.onAutoConfigurationImportEvent(event) :分别通过每个 listern , 处理自动配置导入事件
C05PSC01- AutoConfigurationGroup
?- 该类为内部静态类
M501- process :
- AutoConfigurationImportSelector.getAutoConfigurationEntry(annotationMetadata) : 获取一个 AutoConfigurationEntry 对象
?- 详见 getAutoConfigurationEntry 方法
- this.autoConfigurationEntries.add(autoConfigurationEntry) : 添加到 AutoConfigurationEntry 集合中
FOR- List<AutoConfigurationEntry> : For 循环整个 集合
- this.entries.putIfAbsent(importClassName, annotationMetadata) : 放入 Map<String, AnnotationMetadata>
?- 这里意味着将所有的 AutoConfigurationEntry 重新处理成了 Map
// M501 伪代码
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 调用 M502 生成 AutoConfigurationEntry
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 循环处理加入 放入 Map<String, AnnotationMetadata>
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
// M502 核心伪代码
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);
// 调用处理 Listener
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
复制代码
C06- ConfigurationClass
从 C02-M204 中 ,我们可以看到 , 类上注解以及类中 Bean 都被配置到了 ConfigurationClass , 我们看看相关逻辑是什么样的
C06- ConfigurationClass
- getBeanMethods() : 观察后发现其被调用的地方是 ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
复制代码
C07- ConfigurationClassBeanDefinitionReader
C06M701M702M703加载 BeanDefinitions循环所有的的 @Bean 注解Method如果是 Imported , 调用 702 注册For 循环 loadBeanDefinitionsForBeanMethod判断@Bean @Lazy 等注解处理 autowire 等方法this.registry.registerBeanDefinition 注册C06M701M702M703
C07- ConfigurationClassBeanDefinitionReader
M- loadBeanDefinitions
M701- loadBeanDefinitionsForConfigurationClass
- 判断当前 configClass 是否应该跳过
true : 从相关对象中移除
- this.registry.removeBeanDefinition(beanName)
- this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName())
- 如果是 Imported , 调用 registerBeanDefinitionForImportedConfigurationClass (M702)
FOR- 循环处理 configClass.getBeanMethods() 获得的Bean 方法
- loadBeanDefinitionsForBeanMethod(beanMethod) :M703
M702- registerBeanDefinitionForImportedConfigurationClass
- configClass.getMetadata() : 获取 AnnotationMetadata
- 通过 AnnotationMetadata 生成 AnnotatedGenericBeanDefinition
- 通过 AnnotatedGenericBeanDefinition 生成 ScopeMetadata , 并且为 AnnotatedGenericBeanDefinition 设置 Scope
- 通过 BeanNameGenerator 生成一个 Config BeanName
- 创建一个 BeanDefinitionHolder , 并且 this.registry.registerBeanDefinition 注册
- configClass.setBeanName(configBeanName) : 为 Class 命名
M703- loadBeanDefinitionsForBeanMethod(beanMethod) : 加载 Bean 主逻辑 , 此处已经到了方法处理
- beanMethod.getConfigurationClass() : 获取当前的 ConfigurationClass
- beanMethod.getMetadata() : 获取 MethodMetadata , 该元数据包含当前方法的信息
- 如果当前方法应该跳过 , 则加入到 configClass.skippedBeanMethods , 并且返回
- AnnotationConfigUtils.attributesFor(metadata, Bean.class) : 获取当前方法上 Bean 注解的属性
- bean.getStringArray("name") 获取名称集合 , 取第一个为Bean 名 , 其他的作为别名
- ????
- 通过 configClass 和 metadata 构建一个 ConfigurationClassBeanDefinition
- 为 ConfigurationClassBeanDefinition 设置 extractSource
?- configClass.getResource()
IF- 判断是否为标注 @Bean 的 静态方法
true:
false: 设置 FactoryBeanName 和 UniqueFactoryMethodName
- beanDef.setFactoryBeanName(configClass.getBeanName()) : 设置了当前 config bean 的名称
- beanDef.setUniqueFactoryMethodName(methodName) : 当前 method 的名称
- beanDef.setAutowireMode :设置注入的模式 , 此处是 AUTOWIRE_CONSTRUCTOR
?- AUTOWIRE_NO / AUTOWIRE_BY_NAME / AUTOWIRE_BY_TYPE / AUTOWIRE_CONSTRUCTOR / AUTOWIRE_AUTODETECT
- beanDef.setAttribute : 设置 skipRequiredCheck 为 true
- AnnotationConfigUtils.processCommonDefinitionAnnotations : 设置加载类型
?- 包括 Lazy , Primary , DependsOn , Role , Description
- bean.getEnum("autowire") + beanDef.setAutowireMode(autowire.value())
- bean.getBoolean("autowireCandidate") + setAutowireCandidate
- bean.getString("initMethod") + beanDef.setInitMethodName(initMethodName)
- bean.getString("destroyMethod") + beanDef.setDestroyMethodName(destroyMethodName)
- AnnotationConfigUtils.attributesFor(metadata, Scope.class) : 获取 + beanDef.setScope 配置 Scope 属性
- attributes.getEnum("proxyMode") : 获取 proxyMode
- ScopedProxyCreator.createScopedProxy : 通过获取的 proxyMode + registry + beanDef 等构建 BeanDefinitionHolder
- 通过 BeanDefinitionHolder + configClass + metadata 构建 ConfigurationClassBeanDefinition
- this.registry.registerBeanDefinition(beanName, beanDefToRegister) : 最后注册 Bean
?- registry 是一个 BeanDefinitionRegistry
复制代码
总结
这是一篇测试型的文档 , 想测试一下该以什么样的形式来展现源码流程 , 也不知道这篇文档有没有达到效果.
后续还会对整篇文章继续处理 , 争取找到更合适的模式.
自动装配属于笔记里面比较早期的文章 , 本地还有很多 IOC , Cloud 的文章 , 找到合适的模式后应该能很好的展现了!!