Spring 中@Configuration类中内容解析

837 阅读11分钟

Spring容器初始化 refresh() 方法_03

这篇文章我断断续续写了一礼拜,期待你的点赞。

  上篇文章中讲到invokeBeanFactoryPostProcessor()中有一个非常重要分方法parse(),今天这篇文章中,就来看看这个方法的实现。开始之前,通过下图回顾 一下: 解析配置候选类

5.7 ConfigurationClassParser#parse(Set)

  方法入口如下:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        /** 获取BeanDefinition */
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            /** 根据不同的 BeanDefinition 类型做相应的处理*/
            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);
        }
    }
    this.deferredImportSelectorHandler.process();
}

  这里的 Set<BeanDefinitionHolder> configCandidates 中只有一个元素,就是对 MyConfig 的表述文件 BeanDefinition 的 封装,对应的 BeanDefinitionHolder。通过下图可知,这个类是 AnnotatedBeanDefinition 的实现 MyConfig的BD   按照上图,进入对应的 prase() 方法如下,在该方法中调用对应的 processConfigurationClas() 方法,完成对 ConfigurationClass 的处理。

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

&esnp;  processConfigurationClass() 方法的处理比较复杂,我们先通过流程图简单的看看该方法都做了什么,人后逐个击破: processConfigurationClass流程

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    /**
     * 处理 imported 的情况
     *   就是当前这个注解类有没有被别的类import
     */
    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);
        }
    }
    /** 将对象类型 由ConfigurationClass 转为 SourceClass*/
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        /** 处理 configClass */
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);
    this.configurationClasses.put(configClass, configClass);
}

  在上述方法中,首先判断当前类有没有被别的类 import。在本文中,当前的MyConfig,没有被 Import,因此这里不执行。 然后就是通过 asSourceClass(configClass) 将 配置类转化为 SourceClass 供后续处理。这里的方法对于整个流程来说不重要,我们还是本着抓主要矛盾 的原则,继续往下看,只需要记住,这里的 configClass 转化为 SourceClass 在后面的 doProcessConfigurationClass() 方法中用到。

private SourceClass asSourceClass(ConfigurationClass configurationClass) throws IOException {
    AnnotationMetadata metadata = configurationClass.getMetadata();
    if (metadata instanceof StandardAnnotationMetadata) {
        return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
    }
    return asSourceClass(metadata.getClassName());
}

  每当看到 Spring 中 doXXX 开头的方法,我就知道重头戏要来了,因为,在Spring中,真正做事的都是通过这个方法来处理的,下面就进入到 万众期待的 doProcessConfigurationClass() 里面来一探究竟。。。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {
    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");
        }
    }
    /** 处理 @ComponentScan 注解*/
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        /** 循环处理 componentScans 中的所有属性*/
        for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            /**
             * 扫描普通类,spring 内部开始扫描包的方法
             */
            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
            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());
                }
            }
        }
    }
     /**
     * 处理 @Import
     * 判断类中是否有 @Import 注解 如果有 把 @Import 中的值拿出来,是一个类;
     *   比如 @Import(xxx.class), 这里将 xxx 传进去解析
     *   在解析过程中 如果发现是一个 importSelector 那么就回调 selector 的方法
     *   返回一个字符串(类名), 通过字符串得到一个类。然后递归调用本方法来处理这个类
     */
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    // Process any @ImportResource annotations
    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);
        }
    }
    /**
     * 提取 @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
    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();
        }
    }
    return null;
}

  从上述方法中可以看出,主要对配置类中属性一一作了处理,如:内部类、 @ComponentScan@Important@Bean 。下面将逐个分析。

1. @Configuration 中对内部类的处理

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    // 获取内部类
    Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
    if (!memberClasses.isEmpty()) {
        // 定义 candidates 供后面处理使用
        List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
        for (SourceClass memberClass : memberClasses) {
            // 判断内部类是否为配置候选类 && 内部类的名称 不等于 当前配置类的名称
            if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
                    !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
                // 添加到 候选的 SourceClass 类集合中
                candidates.add(memberClass);
            }
        }
        OrderComparator.sort(candidates);
        for (SourceClass candidate : candidates) {
            if (this.importStack.contains(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            }
            else {
                this.importStack.push(configClass);
                try {
                    // 处理配置类
                    processConfigurationClass(candidate.asConfigClass(configClass));
                }
                finally {
                    this.importStack.pop();
                }
            }
        }
    }
}

  上述代码中有通过 ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) 来判断,内部类是否为配置 候选类。

1.1 判断是否为配置候选类

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    // 判断是是否为全配置候选类 || 判断是否为部分配置候选类
    return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
}

1.2 判断是否为全配置候选类(Full)

public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
    return metadata.isAnnotated(Configuration.class.getName());
}

1.3 判断是否为部分配置候选类(Lite)

public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
    // Do not consider an interface or an annotation...
    if (metadata.isInterface()) {
        return false;
    }

    // Any of the typical annotations found?
    /**
     * {@link candidateIndicators}
     * 中 包含 {@link Component}、{@link ComponentScan}、
     *        {@link Import}、{@link ImportResource}
     */
    for (String indicator : candidateIndicators) {
        if (metadata.isAnnotated(indicator)) {
            return true;
        }
    }

    // Finally, let's look for @Bean methods...
    try {
        return metadata.hasAnnotatedMethods(Bean.class.getName());
    }
    catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
        }
        return false;
    }
}

1.3 Full 与 Lite 配置类的区别

  从上述代码中可以看出,对于内部类中全配置候选类的判断,是通过内部类上的注解来判断的,如果在内部类中加了 @Configuration 注解,Spring 判断其为全配置候选类,如没有加注解,但是有@Bean或者加了@Component@ComponentScan@Import@ImportResource则将其判断为部分配置候选类。具体的定义,是通过静态代码快的方式,添加到 candidateIndicators 中:

static {
  candidateIndicators.add(Component.class.getName());
  candidateIndicators.add(ComponentScan.class.getName());
  candidateIndicators.add(Import.class.getName());
  candidateIndicators.add(ImportResource.class.getName());
 }

  最后对于内部类的处理方式,也是通过调用 processConfigurationClass() 方法来完成相应的处理。也就是说,先经过一系列的判断,将符合 条件的加入到候选类治类的集合中 List<SourceClass> candidates。然后在for循序,拿出每一个配置类,进行相应的处理。

2. @Configuration 中对 @PropertySource 注解的处理

  在Spring 中通过 @PropertySource 来加载指定的属性文件。

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
    String name = propertySource.getString("name");
    if (!StringUtils.hasLength(name)) {
        name = null;
    }
    String encoding = propertySource.getString("encoding");
    if (!StringUtils.hasLength(encoding)) {
        encoding = null;
    }
    String[] locations = propertySource.getStringArray("value");
    Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
    boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

    // 得到创建 PropertySource的工厂
    Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
    //创建 PropertySource的工厂如果是 PropertySourceFactory 就使用Spring 内部默认的 实现 DefaultPropertySourceFactory
    //否则 通过反射创建一个对象
    PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
            DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));

    for (String location : locations) {
        try {
            String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
            Resource resource = this.resourceLoader.getResource(resolvedLocation);
            // 调用factory的createPropertySource方法根据名字、编码、资源创建出一个PropertySource出来
            addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
        }
        catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
            // Placeholders not resolvable or resource not found when trying to open it
            if (ignoreResourceNotFound) {
                if (logger.isInfoEnabled()) {
                    logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
                }
            }
            else {
                throw ex;
            }
        }
    }
}
private void addPropertySource(PropertySource<?> propertySource) {
    String name = propertySource.getName();
    MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment).getPropertySources();

    if (this.propertySourceNames.contains(name)) {
        // We've already added a version, we need to extend it
        PropertySource<?> existing = propertySources.get(name);
        if (existing != null) {
            PropertySource<?> newSource = (propertySource instanceof ResourcePropertySource ?
                    ((ResourcePropertySource) propertySource).withResourceName() : propertySource);
            if (existing instanceof CompositePropertySource) {
                ((CompositePropertySource) existing).addFirstPropertySource(newSource);
            }
            else {
                if (existing instanceof ResourcePropertySource) {
                    existing = ((ResourcePropertySource) existing).withResourceName();
                }
                CompositePropertySource composite = new CompositePropertySource(name);
                composite.addPropertySource(newSource);
                composite.addPropertySource(existing);
                propertySources.replace(name, composite);
            }
            return;
        }
    }

    if (this.propertySourceNames.isEmpty()) {
        propertySources.addLast(propertySource);
    }
    else {
        String firstProcessed = this.propertySourceNames.get(this.propertySourceNames.size() - 1);
        propertySources.addBefore(firstProcessed, propertySource);
    }
    this.propertySourceNames.add(name);
}

  我在这里暂时没有用到, @PropertySource 注解,这里先指出代码的处理,后面用到的时候,在做详细的介绍。这里,我们先对这部分内容过掉。

3. @Configuration 中对 @ComponentScan 注解的处理

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    /**
     * new 一个 ClassPathBeanDefinitionScanner 的 scanner 扫描包
     */
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
            BeanUtils.instantiateClass(generatorClass));

    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    }
    else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addIncludeFilter(typeFilter);
        }
    }
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addExcludeFilter(typeFilter);
        }
    }

    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }

    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });
    /**
     * 在这里做doScan()
     */
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

  从这里可以看出,对于包的扫描,是在扫描的时候 new ClassPathBeanDefinitionScanner() 创建的扫描器来完成扫描的,并不是使用 AnnotationConfigApplicationContext 中初始化的扫描器来完成包扫描的。

3.1 doScan()

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        /**
         * 扫描basePackage路径下的 java 文件
         * 将其转换为BeanDefinition
         */
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);


        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            /**
             * 如果 candidate 是 AbstractBeanDefinition 的子类
             */
            if (candidate instanceof AbstractBeanDefinition) {
                /** 为 candidate 设置默认值*/
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                /**
                 * 如果 candidate 是 AnnotatedBeanDefinition 的子类
                 * 检查并处理常用的注解,把值设置到 AnnotatedBeanDefinition 中
                 * 这里只有被加了注解的类才会被处理
                 */
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                /** 加入到 Map 当中*/
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

  又是熟悉的doXXX()方法,通过这个方法,将我们定义的包路径下的对象添加到IoC容器中去当然,在注册到容器中之前,也要对扫描得到的BeanDeifition的属性进行处理,如通用的注解

3.2 通用注解的处理

/**
 * 处理类的通用注解
 * @param abd spring中bean的描述类
 */
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
    processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

/**
 *  处理类的通用注解
 * @param abd spring中bean的描述类
 * @param metadata 通过spring中bean的描述类获取 bean的元数据信息
 *
 *       处理完通用注解后的信息 放回到 spring中bean的描述类(AnnotatedBeanDefinition)
 */
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
    /**
     * 处理 @Lazy 注解
     */
    AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
    if (lazy != null) {
        /** 设置bean的懒加载信息*/
        abd.setLazyInit(lazy.getBoolean("value"));
    }
    else if (abd.getMetadata() != metadata) {
        lazy = attributesFor(abd.getMetadata(), Lazy.class);
        if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
        }
    }

    /**
     * 处理 @Primary 注解
     */
    if (metadata.isAnnotated(Primary.class.getName())) {
        abd.setPrimary(true);
    }

    /**
     * 处理 @DependsOn 注解
     */
    AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    if (dependsOn != null) {
        abd.setDependsOn(dependsOn.getStringArray("value"));
    }

    /**
     * 处理 @Role 注解
     */
    AnnotationAttributes role = attributesFor(metadata, Role.class);
    if (role != null) {
        abd.setRole(role.getNumber("value").intValue());
    }

    /**
     * 处理 @Description注解
     */
    AnnotationAttributes description = attributesFor(metadata, Description.class);
    if (description != null) {
        abd.setDescription(description.getString("value"));
    }
}

3.3 对扫描出来的类注册

if (checkCandidate(beanName, candidate)) {
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    definitionHolder =
            AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    beanDefinitions.add(definitionHolder);
    /** 加入到 Map 当中*/
    registerBeanDefinition(definitionHolder, this.registry);
}

  通过这里,就可以将我们自己交给Spring管理的类,注册到了容器当中,对应的我们的容器形成图例里面的内容也相应的增加了:

3.3.1容器中的对象
容器中的对象
容器中的对象
3.3.2容器中的对象名称
容器中的对象名称
容器中的对象名称
3.3.3容器形成图
容器形成图
容器形成图

4. @Configuration 中对 @Import(xxx.class) 的处理

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 {
        this.importStack.push(configClass);
        try {
            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 (selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    }
                    else {
                        /** 回调*/
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        /**
                         * 递归,这里第二次调用 processImports
                         * 如果是一个普通的类 会进 else
                         */
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                }
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    /**
                     * 判断Import的是不是 ImportBeanDefinitionRegistrar
                     */
                    // 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
                    /**
                     * 普通类的处理方式
                     * 加入到 importStack 后调用 processConfigurationClass 进行处理
                     * processConfigurationClass 里面主要就是把类放到 configurationClasses 中
                     * configurationClasses 是一个集合 会在后面拿出来解析成bd 接续注册
                     * 注意:
                     *    普通类实在扫描出来的时候就被注册了
                     *    importSelector 会放到 configurationClasses 中 然后进行注册
                     */
                    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();
        }
    }
}

5. @Configuration 中对 @Bean 方法 信息的提取

  获取当前类中 @Bean 注解的方法的元数据,包含比如方法名、所在类全名、返回类型、是否静态、是否不可覆盖等等信息。

private Set<MethodMetadata> retrieveBeanMethodMetadata(SourceClass sourceClass) {
    /** 获取类的元数据*/
    AnnotationMetadata original = sourceClass.getMetadata();
    /** 获取所有@Bean注解的方法*/
    Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
    /** 判断方法集合是否超过两个,并且类的元数据是StandardAnnotationMetadata实例,则从ASM内获取声明的方法顺序*/
    if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
        // Try reading the class file via ASM for deterministic declaration order...
        // Unfortunately, the JVM's standard reflection returns methods in arbitrary
        // order, even between different runs of the same application on the same JVM.
        try {
            AnnotationMetadata asm =
                    this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
            Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
            if (asmMethods.size() >= beanMethods.size()) {
                Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
                for (MethodMetadata asmMethod : asmMethods) {
                    for (MethodMetadata beanMethod : beanMethods) {
                        if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
                            selectedMethods.add(beanMethod);
                            break;
                        }
                    }
                }
                if (selectedMethods.size() == beanMethods.size()) {
                    // All reflection-detected methods found in ASM method set -> proceed
                    beanMethods = selectedMethods;
                }
            }
        }
        catch (IOException ex) {
            logger.debug("Failed to read class file via ASM for determining @Bean method order", ex);
            // No worries, let's continue with the reflection metadata we started with...
        }
    }
    return beanMethods;
}

6.总结

  在Spring的处理配置类的过程中,通过 parser.parse(candidates); 方法完成了对配置类的解析。包括配置类上的注解@ComponentScan@Import、``配置类中的属性如:@Bean()方法,当前类中通过@Component注入的内部类,以及通过@Configuration注入的内类的区分与解析。

  Spring中对于@Congfiguration注解的配置类,与其他形式的配置类会进行标记,就是上面提到的FullLite两种标记。

本文使用 mdnice 排版