zoukankan      html  css  js  c++  java
  • Spring 工具类 ConfigurationClassParser 分析得到配置类

    https://blog.csdn.net/andy_zhang2007/article/details/78549773

    Spring 工具类 ConfigurationClassParser 分析得到配置类
    原创安迪源文 最后发布于2017-11-16 12:19:50 阅读数 4296 收藏
    展开
    简介
    Spring的工具类ConfigurationClassParser用于分析@Configuration注解的配置类,产生一组ConfigurationClass对象。它的分析过程会接受一组种子配置类(调用者已知的配置类,通常很可能只有一个),从这些种子配置类开始分析所有关联的配置类,分析过程主要是递归分析配置类的注解@Import,配置类内部嵌套类,找出其中所有的配置类,然后返回这组配置类。

    该工具主要由ConfigurationClassPostProcessor使用,而ConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor,它会在容器启动过程中,应用上下文上执行各个BeanFactoryPostProcessor时被执行。

    ConfigurationClassParser 所在包 : org.springframework.context.annotation

    这个工具类自身的逻辑并不注册bean定义,它的主要任务是发现@Configuration注解的所有配置类并将这些配置类交给调用者(调用者会通过其他方式注册其中的bean定义),而对于非@Configuration注解的其他bean定义,比如@Component注解的bean定义,该工具类使用另外一个工具ComponentScanAnnotationParser扫描和注册它们。

    该工具类对@ComponentScans,@ComponentScan注解的处理使用了ComponentScanAnnotationParser,ComponentScanAnnotationParser在扫描到bean定义时会直接将其注册到容器,而不是采用和ConfigurationClassParser类似的方式交由调用者处理。

    一般情况下一个@Configuration注解的类只会产生一个ConfigurationClass对象,但是因为@Configuration注解的类可能会使用注解@Import引入其他配置类,也可能内部嵌套定义配置类,所以总的来看,ConfigurationClassParser分析一个@Configuration注解的类,可能产生任意多个ConfigurationClass对象。

    主要功能分析
    以下源代码基于 Spring 4.3.12.RELEASE

    parse() : 外部调用入口
    parse()方法的主体工作流程 :

    接收外部提供的参数 configCandidates , 是一组需要被分析的候选配置类的集合,每个元素使用类型BeanDefinitionHolder包装 ;
    parse() 方法针对每个候选配置类元素BeanDefinitionHolder,执行以下逻辑 :
    1.将其封装成一个ConfigurationClass
    2.调用processConfigurationClass(ConfigurationClass configClass)
    > 分析过的每个配置类都被保存到属性 this.configurationClasses 中。
    /**
    * @参数 configCandidates : 外部指定需要被分析的一组候选配置类
    **/
    public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

    for (BeanDefinitionHolder holder : configCandidates) {
    BeanDefinition bd = holder.getBeanDefinition();
    try {
    // 这里根据Bean定义的不同类型走不同的分支,但是最终都会调用到方法
    // processConfigurationClass(ConfigurationClass configClass)
    if (bd instanceof AnnotatedBeanDefinition) {
    // bd 是一个 AnnotatedBeanDefinition
    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
    }
    else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
    // bd 是一个 AbstractBeanDefinition,并且指定 beanClass 属性
    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);
    }
    }

    // 执行找到的 DeferredImportSelector
    // DeferredImportSelector 是 ImportSelector 的一个变种。
    // ImportSelector 被设计成其实和@Import注解的类同样的导入效果,但是实现 ImportSelector
    // 的类可以条件性地决定导入哪些配置。
    // DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。这也正是
    // 该语句被放到本函数最后一行的原因。
    processDeferredImportSelectors();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    processConfigurationClass() 分析一个配置类
    processConfigurationClass()对配置的处理并不是真正自己处理,而是开始一个基于doProcessConfigurationClass()的处理循环,该循环从参数配置类开始遍历其所有需要处理的父类(super),每个类都使用doProcessConfigurationClass()来处理。每处理一个类,processConfigurationClass()将其记录到this.configurationClasses。

    /**
    * 用于分析一个 ConfigurationClass,分析之后将它记录到已处理配置类记录
    **/
    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
    return;
    }

    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
    if (configClass.isImported()) {
    if (existingClass.isImported()) {
    //如果要处理的配置类configClass在已经分析处理的配置类记录中已存在,
    //合并二者的importedBy属性
    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);
    for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext();) {
    if (configClass.equals(it.next())) {
    it.remove();
    }
    }
    }
    }

    // Recursively process the configuration class and its superclass hierarchy.
    // 从当前配置类configClass开始向上沿着类继承结构逐层执行doProcessConfigurationClass,
    // 直到遇到的父类是由Java提供的类结束循环
    SourceClass sourceClass = asSourceClass(configClass);
    do {
    // 循环处理配置类configClass直到sourceClass变为null
    // doProcessConfigurationClass的返回值是其参数configClass的父类,
    // 如果该父类是由Java提供的类或者已经处理过,返回null
    sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    // 需要被处理的配置类configClass已经被分析处理,将它记录到已处理配置类记录
    this.configurationClasses.put(configClass, configClass);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    processDeferredImportSelectors() 处理需要延迟处理的ImportSelector
    /**
    * 对属性deferredImportSelectors中记录的DeferredImportSelector进行处理
    **/
    private void processDeferredImportSelectors() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

    // 循环处理每个DeferredImportSelector
    for (DeferredImportSelectorHolder deferredImport : deferredImports) {
    ConfigurationClass configClass = deferredImport.getConfigurationClass();
    try {
    //调用DeferredImportSelector的方法selectImports,获取需要被导入的类的名称
    String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
    // 处理任何一个 @Import 注解
    processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
    }
    catch (BeanDefinitionStoreException ex) {
    throw ex;
    }
    catch (Throwable ex) {
    throw new BeanDefinitionStoreException(
    "Failed to process import candidates for configuration class [" +
    configClass.getMetadata().getClassName() + "]", ex);
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    doProcessConfigurationClass()对一个配置类执行真正的处理
    doProcessConfigurationClass()会对一个配置类执行真正的处理:

    一个配置类的成员类(配置类内嵌套定义的类)也可能适配类,先遍历这些成员配置类,调用processConfigurationClass处理它们;
    处理配置类上的注解@PropertySources,@PropertySource
    处理配置类上的注解@ComponentScans,@ComponentScan
    处理配置类上的注解@Import
    处理配置类上的注解@ImportResource
    处理配置类中每个带有@Bean注解的方法
    处理配置类所实现接口的缺省方法
    检查父类是否需要处理,如果父类需要处理返回父类,否则返回null
    返回父类表示当前配置类处理尚未完成,调用者processConfigurationClass会继续处理其父类;返回null才表示该配置类的处理完成。从这里可以推断一旦一个配置类被processConfigurationClass处理完成,表示其自身,内部嵌套类,各个实现接口以及各级父类都被处理完成。

    /**
    * Apply processing and build a complete ConfigurationClass by reading the
    * annotations, members and methods from the source class. This method can be called
    * multiple times as relevant sources are discovered.
    * @param configClass the configuration class being build
    * @param sourceClass a source class
    * @return the superclass, or null if none found or previously processed
    */
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
    throws IOException {

    // 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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
    "]. Reason: Environment must implement ConfigurableEnvironment");
    }
    }

    // Process any @ComponentScan annotations,处理每个@ComponentScan注解
    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) {
    // 该配置类上注解了@ComponentScan,现在执行扫描,获取其中的Bean定义
    // this.componentScanParser 是一个 ComponentScanAnnotationParser,在当前对象的构造函数中
    // 被创建
    Set<BeanDefinitionHolder> scannedBeanDefinitions =
    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    // 对Component scan得到的Bean定义做检查,看看里面是否有需要处理的配置类,
    // 有的话对其做分析处理
    for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
    if (ConfigurationClassUtils.checkConfigurationClassCandidate(
    holder.getBeanDefinition(), this.metadataReaderFactory)) {
    // 如果该Bean定义是一个配置类,它进行分析
    parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
    }
    }
    }
    }

    // Process any @Import annotations,处理每个@Import注解
    // 注意这里调用到了getImports()方法,它会搜集sourceClass上所有的@Import注解的value值,
    // 具体搜集的方式是访问sourceClass直接注解的@Import以及递归访问它的注解中隐含的所有的@Import
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // Process any @ImportResource annotations,处理每个@ImportResource注解
    if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
    AnnotationAttributes importResource =
    AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    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注解的方法
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
    configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // Process default methods on interfaces,处理接口上的缺省方法
    processInterfaces(configClass, sourceClass);

    // Process superclass, if any
    // 如果父类superclass存在,并且不是`java`包中的类,并且尚未处理处理,
    // 则才返回它以便外层循环继续
    if (sourceClass.getMetadata().hasSuperClass()) {
    String superclass = sourceClass.getMetadata().getSuperClassName();
    if (!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;// 用返回null告诉外层循环结束
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    processImports()处理配置类上搜集到的@Import注解
    /**
    * 处理配置类上搜集到的@Import注解
    * 参数 configuClass 配置类
    * 参数 currentSourceClass 当前源码类
    * 参数 importCandidates, 所有的@Import注解的value
    * 参数 checkForCircularImports, 是否检查循环导入
    **/
    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
    Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {

    if (importCandidates.isEmpty()) {
    // 如果配置类上没有任何候选@Import,说明没有需要处理的导入,则什么都不用做,直接返回
    return;
    }

    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
    // 如果要求做循环导入检查,并且检查到了循环依赖,报告这个问题
    this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
    // 开始处理配置类configClass上所有的@Import importCandidates
    this.importStack.push(configClass);
    try {
    // 循环处理每一个@Import,每个@Import可能导入三种类型的类 :
    // 1. ImportSelector
    // 2. ImportBeanDefinitionRegistrar
    // 3. 其他类型,都当作配置类处理,也就是相当于使用了注解@Configuration的配置类
    // 下面的for循环中对这三种情况执行了不同的处理逻辑
    for (SourceClass candidate : importCandidates) {
    if (candidate.isAssignable(ImportSelector.class)) {
    // Candidate class is an ImportSelector -> delegate to it to determine imports
    Class<?> candidateClass = candidate.loadClass();
    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
    ParserStrategyUtils.invokeAwareMethods(
    selector, this.environment, this.resourceLoader, this.registry);
    if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
    this.deferredImportSelectors.add(
    new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
    }
    else {
    String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
    Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
    processImports(configClass, currentSourceClass, importSourceClasses, false);
    }
    }
    else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
    // Candidate class is an ImportBeanDefinitionRegistrar ->
    // delegate to it to register additional bean definitions
    Class<?> candidateClass = candidate.loadClass();
    ImportBeanDefinitionRegistrar registrar =
    BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
    ParserStrategyUtils.invokeAwareMethods(
    registrar, 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
    this.importStack.registerImport(
    currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
    processConfigurationClass(candidate.asConfigClass(configClass));
    }
    }
    }
    catch (BeanDefinitionStoreException ex) {
    throw ex;
    }
    catch (Throwable ex) {
    throw new BeanDefinitionStoreException(
    "Failed to process import candidates for configuration class [" +
    configClass.getMetadata().getClassName() + "]", ex);
    }
    finally {
    this.importStack.pop();
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    相关文章
    Spring 工具类 ComponentScanAnnotationParser 扫描和定义组件bean
    Spring BeanDefinitionRegistryPostProcessor : ConfigurationClassPostProcessor
    Spring 工具类 ConfigurationClassBeanDefinitionReader 注册配置类中的bean定义

    点赞 3
    收藏
    分享

    安迪源文 博客专家
    发布了528 篇原创文章 · 获赞 106 · 访问量 41万+
    他的留言板
    关注

    ————————————————
    版权声明:本文为CSDN博主「安迪源文」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/andy_zhang2007/article/details/78549773

  • 相关阅读:
    Hadoop学习------Hadoop安装方式之(一):单机部署
    Linux系统上安装、卸载JAVA、TOMCAT的方法
    在Linux系统上安装Oracle数据库
    C:Program Files (x86)MSBuild14.0inMicrosoft.Common.CurrentVersion.targets(4714,5): error MSB30...
    软件设计,数据库结构设计,设计思想
    面试题 SqlServer知识
    @Ajax.ActionLink跳转页面的问题解决方案 MVC Ajax不支持问题
    .net机试题总结
    .Net机试题——编写一个BS架构的多层表结构的信息管理模块
    C# 不同类型对象同名属性赋值
  • 原文地址:https://www.cnblogs.com/zhoading/p/12195625.html
Copyright © 2011-2022 走看看