Инвентарь SpringBoot: Автопроводка

Java
Инвентарь SpringBoot: Автопроводка

Общая документация:Каталог статей
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

M101M102M102 doWhileперечислитьобработка цикла синтаксического анализа do-whileОбработка ConfigurationClassParserОбработка ConfigurationClassBeanDefinitionReaderОценка обработанных и создание новых необработанныхКандидаты пусты, обработка завершенаЗарегистрируйте 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вызов процессаConfigurationClassвызов doProcessConfigurationClassЦикл через PropertySourcesЦикл через ComponentScansПроцесс @bean метод рекурсивноРекурсивная обработка @Importполучить суперклассвернуть суперкласс или нольРекурсивно обрабатывать суперклассыДобавьте класс обработчика в коллекцию 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После получения всех группВызовите processGroupImports для обработки группыПолучить DeferredImportSelectorHolder в общей логике обработки группового процессаВыполнение общей логики обработки группового процесса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перечислитьПолучить AutoConfigurationEntry через AnnotationMetadataПолучить список всех конфигурацийФильтровать дубликаты и фильтровать ConfigClasses, которые необходимо пропуститьОбработка слушателей и событийВозвращает AutoConfigurationEntryAutoConfigurationEntry добавлен MapM401M501M502M503

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Загрузить определения компонентовПеребрать все аннотированные методы @BeanЕсли это импорт, позвоните по номеру 702, чтобы зарегистрироваться.Для цикла loadBeanDefinitionsForBeanMethodОценка аннотаций, таких как @Bean @LazyМетоды обработки, такие как autowirethis.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.Найдя подходящий мод,должно хорошо отображаться!!