专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

Spring 中@Configuration类中内容解析

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

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

  上篇文章中讲到invokeBeanFactoryPostProcessor()中有一个非常重要分方法parse(),今天这篇文章中,就来看看这个方法的实现。开始之前,通过下图回顾 一下: 121_1.png

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 的实现 121_2.png   按照上图,进入对应的 prase() 方法如下,在该方法中调用对应的 processConfigurationClas() 方法,完成对 ConfigurationClass 的处理。

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

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

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容器中的对象

121_4.png 容器中的对象

3.3.2容器中的对象名称

121_5.png 容器中的对象名称

3.3.3容器形成图

121_6.png 容器形成图

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 排版

文章永久链接:https://tech.souyunku.com/28077

未经允许不得转载:搜云库技术团队 » Spring 中@Configuration类中内容解析

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们