Общая документация:Каталог статей
Github : github.com/black-ant
Введение
Я случайно доделал соответствующий исходный код автоматической сборки, поэтому наконец-то могу открыть эту серию.
В этой серии мы подошли к автоматическому процессу сборки, и весь процесс начинает учиться с года, не нашел подходящего выражения в форме.В последнее время я вдохновился, просто попробуйте этот способ.
2. Очки базовых знаний
2.1 Основная информация
Автоматическая настройка Spring Boot пытается автоматически настроить приложения Spring на основе добавленных зависимостей jar, а Spring расширяет гибкость Spring, предоставляя альтернативы автоматическому подключению и самостоятельной настройке.
Разумеется, конфигурация не может быть сгенерирована просто так, откройте пакет Spring-boot-autoconfigure и вы увидите соответствующие файлы конфигурации:
- 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, пакеты jar, связанные с Spring MVC, автоматически вводятся для автоматической настройки Spring MVC.
- Autowiring: это метод внедрения IoC, предоставляемый Spring.Подробности см. в документе «Spring Tutorial — Beans Autowiring».
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. Анализ исходного кода
Давайте попробуем новый способ парсить исходный код:
3.1 Начальная точка сканирования
3.2 Взаимоотношения сканирования службы
Сначала рассмотрим основную логику:
1.Начал ConfigurationCassPostProcessor.
2.Получить всю информацию о классе конфигурации в doProcessConfigurationClass класса ConfigurationClassPostProcessor, включая bean-компоненты, помеченные @Bean
3.Наконец загружен в loadBeanDefinitionsForBeanMethod of ConfigurationClassBeanDefinitionReader
C01- ConfigurationClassPostProcessor: обработать тип processConfigBeanDefinitions
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.
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
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.
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
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.Найдя подходящий мод,должно хорошо отображаться!!