Spring源码之@Configuration注解解析

1.前言 ​

Spring注解开发中,我们只需求要类上加上@Configuration注解,然后在类中的方法上面加上@Bean注解即可完成Spring Bean组件的注册。相较于之前的xml配置文件定义注册组件简化了非常多。那么Spring底层是如何处理@Configuration注解来完成Spring组件的注册,下面通过源码一步一步进行分析。

2.准备工作

Spring版本:2.2.13.RELEASE

源码中涉及的类:

  • ConfigurationClassPostProcessor
  • ConfigurationClassParser
  • ConfigurationClass
  • BeanMethod
  • ConfigurationClassBeanDefinitionReader
  • ConfigurationClassEnhancer
  • ConfigurationClassUtils

说明:文中统一将被@Configuration注解标注的类称为配置类

3.涉及相关类说明

ConfigurationClassPostProcessor
 配置类的后知处理器,其中实现了BeanDefinitionRegistryPostProcessor接口,可以拿到BeanDefinitionRegistry对象手动注册组件,也是整个解析流程的入口
ConfigurationClassParser
 配置类解析器,解析配置类,封装成一个个的ConfigurationClass对象
ConfigurationClass
 配置类经解析后的实体对象
BeanMethod
 被@Bean注解标注的方法解析后的实体对象
ConfigurationClassBeanDefinitionReader
 用于读取注册配置类中定义的组件
ConfigurationClassEnhancer
 对配置类进行代理增强的角色类
ConfigurationClassUtils
 配置类解析相关的工具类

4.源码流程分析

ConfigurationClassPostProcessor作为入口类,类的层次结构入上图,我们只需要关心BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor两个接口的回调方法BeanFactoryPostProcessor和postProcessBeanFactory。

两个方法的具体实现如下,可以看到两个方法的内部都调用了processConfigBeanDefinitions方法,下面针对此方法进行分析

 1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
 2         int registryId = System.identityHashCode(registry);
 3         if (this.registriesPostProcessed.contains(registryId)) {
 4             throw new IllegalStateException(
 5                     "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
 6         }
 7         if (this.factoriesPostProcessed.contains(registryId)) {
 8             throw new IllegalStateException(
 9                     "postProcessBeanFactory already called on this post-processor against " + registry);
10         }
11         this.registriesPostProcessed.add(registryId);
12 
13         processConfigBeanDefinitions(registry);
14     }
15 
16 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
17         int factoryId = System.identityHashCode(beanFactory);
18         if (this.factoriesPostProcessed.contains(factoryId)) {
19             throw new IllegalStateException(
20                     "postProcessBeanFactory already called on this post-processor against " + beanFactory);
21         }
22         this.factoriesPostProcessed.add(factoryId);
23         if (!this.registriesPostProcessed.contains(factoryId)) {
24             // BeanDefinitionRegistryPostProcessor hook apparently not supported...
25             // Simply call processConfigurationClasses lazily at this point then.
26             processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
27         }
28 
29         enhanceConfigurationClasses(beanFactory);
30         beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
31     }

1.processConfigBeanDefinitions方法分析如下(删除了部分不相关代码)

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        // 待处理配置类集合
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        // 获取所有组件名称
        String[] candidateNames = registry.getBeanDefinitionNames();

        for (String beanName : candidateNames) {
            // 获取组件定义信息
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            // 判断组件是否已经被作为一个配置类处理过
            if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            // 判断组件是否为候选的配置类,如果是则加入待处理集合。checkConfigurationClassCandidate下面具体分析
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        // 如果待处理配置类为空,直接返回
        if (configCandidates.isEmpty()) {
            return;
        }

        // 对所有配置类进行排序
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return Integer.compare(i1, i2);
        });
       // 初始化配置类解析器
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);do {
            // 解析每一个配置类
            parser.parse(candidates);
            // 验证每一个配置类
            parser.validate();
            // 获取解析后的所有配置类实体ConfigurationClass
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            // 初始化配置类中定义的组件读取者
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }

            // 读取配置类中所有被@Bean注解标注的方法,并将每个方法封装成BeanDefinition注册到容器中
            this.reader.loadBeanDefinitions(configClasses);
        }
        while (!candidates.isEmpty());
    }

2.ConfigurationClassUtils.checkConfigurationClassCandidate方法分析

public static boolean checkConfigurationClassCandidate(
            BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

        // 获取组件的全限定类名
        String className = beanDef.getBeanClassName();
        if (className == null || beanDef.getFactoryMethodName() != null) {
            return false;
        }

        // 下面这一大段代码都是在获取组件类的元数据信息AnnotationMetadata,这里不详细介绍
        AnnotationMetadata metadata;
        if (beanDef instanceof AnnotatedBeanDefinition &&
                className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
            // Can reuse the pre-parsed metadata from the given BeanDefinition...
            metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
        }
        else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
            // Check already loaded Class if present...
            // since we possibly can't even load the class file for this Class.
            Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
            if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
                    BeanPostProcessor.class.isAssignableFrom(beanClass) ||
                    AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
                    EventListenerFactory.class.isAssignableFrom(beanClass)) {
                return false;
            }
            metadata = AnnotationMetadata.introspect(beanClass);
        }
        else {
            try {
                MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
                metadata = metadataReader.getAnnotationMetadata();
            }
            catch (IOException ex) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not find class file for introspecting configuration annotations: " +
                            className, ex);
                }
                return false;
            }
        }

        // 获取组件类的@Configuration注解属性,如果组件类上不存在@Configuration注解,则返回空
        Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
        // 如果存在,并且proxyBeanMethods属性的值为true,则标注当前配置类为full,即需要代理增强,为一个代理类
        if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
        }
        // 如果存在,并且isConfigurationCandidate返回true,则标注当前配置类为lite,即不需要代理增强,为一个普通类
        else if (config != null || isConfigurationCandidate(metadata)) {
            beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
        }
        // 组件类不存在@Configuration注解,直接返回false
        else {
            return false;
        }

        // 获取配置类的排序顺序,设置到组件定义属性中
        Integer order = getOrder(metadata);
        if (order != null) {
            beanDef.setAttribute(ORDER_ATTRIBUTE, order);
        }

        return true;
    }

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
   // 如果配置类为一个接口,则不处理
   if (metadata.isInterface()) {
      return false;
   }

   /*
    * 判断配置类是否存在(@Component,ComponentScan,@Import,ImportResource)注解
    * 如果存在上述任意一个注解,则返回true
    */
   for (String indicator : candidateIndicators) {
      if (metadata.isAnnotated(indicator)) {
         return true;
      }
   }

   // 如果上述四个注解都不存在,则判断配置类中是否存在被@Bean标注的方法
   return hasBeanMethods(metadata);
}

3.ConfigurationClassParser.parse方法分析

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        for (BeanDefinitionHolder holder : configCandidates) {
            // 循环每一个配置类的定义信息,然后调用parse方法,下面三个parse重载方法逻辑一样
            BeanDefinition bd = holder.getBeanDefinition();
            try {
                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();
    }

    protected final void parse(@Nullable String className, String beanName) throws IOException {
        Assert.notNull(className, "No bean class name for configuration class bean definition");
        MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
        // 将配置类封装成ConfigurationClass后调用processConfigurationClass
        processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
    }

    protected final void parse(Class<?> clazz, String beanName) throws IOException {
        // 将配置类封装成ConfigurationClass后调用processConfigurationClass
        processConfigurationClass(new ConfigurationClass(clazz, beanName), DEFAULT_EXCLUSION_FILTER);
    }

    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
        // 将配置类封装成ConfigurationClass后调用processConfigurationClass
        processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
    }

4.processConfigurationClass方法分析

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        // 判断配置类是否有@Condition注解,如果有的话根据条件判断是否成立
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }
// 递归处理配置类和其所有父类
        SourceClass sourceClass = asSourceClass(configClass, filter);
        do {
            sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
        }
        while (sourceClass != null);
        
    }

5.doProcessConfigurationClass方法分析

protected final SourceClass doProcessConfigurationClass(
            ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
            throws IOException {

        // 判断配置类上的注解层次中是否包含@Component注解,如果包含则递归获取内部类进行处理
        if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            // 递归处理所有的内部类
            processMemberClasses(configClass, sourceClass, filter);
        }

        // 处理配置类上注解层次中的所有@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)) {
            for (AnnotationAttributes componentScan : componentScans) {
                // The config class is annotated with @ComponentScan -> perform the scan immediately
                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注解
        processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

        // 处理配置类上注解层次中的所有@ImportResource注解
        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注解的方法,并封装成BeanMethod添加到配置类的实体ConfigurationClass中
        Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
        for (MethodMetadata methodMetadata : beanMethods) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
        }

        // Process default methods on interfaces
        processInterfaces(configClass, sourceClass);

        // 如果有父类,则返回父类
        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();
            }
        }

        // 没有父类,返回null
        return null;
    }

6.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions方法分析

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        // 可跟踪记录的条件评估者,也就是解析@Conditon注解的作用,并且可以记录满足@Condition和不满足@Condition的原因
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            // 从配置类中加载组件定义信息
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
}

   
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

        // 处理配置类上的@Condition注解
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }

        // 判断当前配置类是否是通过@Import注解导入的
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        // 获取配置类中的所有@Bean注解标注的方法
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            // 从@Bean标注的方法加载组件定义信息
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }

        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

7.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod方法分析

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        // 获取配置类信息
        ConfigurationClass configClass = beanMethod.getConfigurationClass();
        MethodMetadata metadata = beanMethod.getMetadata();
        // 获取方法名
        String methodName = metadata.getMethodName();

        // 处理方法上的@Conditional注解
        if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
            configClass.skippedBeanMethods.add(methodName);
            return;
        }
        if (configClass.skippedBeanMethods.contains(methodName)) {
            return;
        }

        // 获取方法上@Bean注解的属性信息
        AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
        Assert.state(bean != null, "No @Bean annotation attributes");

        // 处理@Bean注解的name属性,如果此属性为空,则组件的名称为方法名
        List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
        String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

        // 将name属性的值注册为此组件的别名
        for (String alias : names) {
            this.registry.registerAlias(beanName, alias);
        }
     // 将@Bean方法封装成BeanDefinition
        ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata, beanName);
        beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

        // 如果@Bean方法为静态方法
        if (metadata.isStatic()) {
            // static @Bean method
            if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
                beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
            }
            else {
                beanDef.setBeanClassName(configClass.getMetadata().getClassName());
            }
            beanDef.setUniqueFactoryMethodName(methodName);
        }
        // 如果@Bean方法为实例方法
        else {
            beanDef.setFactoryBeanName(configClass.getBeanName());
            beanDef.setUniqueFactoryMethodName(methodName);
        }

        beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
        beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
                SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

        /*
            处理@Bean方法上的公共注解(@Lazy,@Primary,@DependsOn,@Role,@Description)
            这里稍微解释一下这几个注解
                @Lazy:组件是否为懒加载,组件的创建可以在项目启动Spring容器刷新的时候创建,也可以在第一次获取组件的时候(BeanFactory.getBean)创建。后者则为懒加载
                @Primary:如果一个接口在容器中有多个实现类的时候,在使用@Autowired依赖注入的时候优先使用被@Primary注解标注的实现类
                @DependsOn:创建此组件时依赖的其他组件,在创建此组件时,先创建完成依赖的其他组件
                @Role:组件的角色,Spring框架底层使用。开发者一般不用
                @Description:可以为组件定义添加描述,相当于一个描述信息,仅此而已
        */
        AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

        // 下面一段都是处理@Bean注解的各个属性
        Autowire autowire = bean.getEnum("autowire");
        if (autowire.isAutowire()) {
            beanDef.setAutowireMode(autowire.value());
        }

        boolean autowireCandidate = bean.getBoolean("autowireCandidate");
        if (!autowireCandidate) {
            beanDef.setAutowireCandidate(false);
        }

        String initMethodName = bean.getString("initMethod");
        if (StringUtils.hasText(initMethodName)) {
            beanDef.setInitMethodName(initMethodName);
        }

        String destroyMethodName = bean.getString("destroyMethod");
        beanDef.setDestroyMethodName(destroyMethodName);
     // 将组件定义注册到容器中
        this.registry.registerBeanDefinition(beanName, beanDefToRegister);
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值