Spring之基于Java类的配置bean的加载注册流程

描述

Spring Bean定义的三种方式:

  1. 基于XML的配置
  2. 基于注解的配置,在类中加入如下注解通过包扫描加载注册bean:
    @Component:当对组件的层次难以定位的时候使用这个注解
    @Controller:表示控制层的组件
    @Service:表示业务逻辑层的组件
    @Repository:表示数据访问层的组件
  1. 基于Java类的配置:
  • 使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
  • 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。

下面跟踪源码查看spring基于Java类的配置定义bean的加载注册流程

Java类配置的模型

  • @Configuration描述的类模型ConfigurationClass
 final class ConfigurationClass {

    /**
     * 注解元数据
     */
    private final AnnotationMetadata metadata;

    /**
     * 资源信息
     */
    private final Resource resource;

    /**
     * bean定义的名称
     */
    @Nullable
    private String beanName;

    /**
     * import 注解导入的配置类(被@Configuration注解的类)集合
     */
    private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);

    /**
     * 配置类下被@Bean注解的方法结合
     */
    private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();

    /**
     * 跳过的方法名集合
     */
    final Set<String> skippedBeanMethods = new HashSet<>();
}   

ConfigurationClass 类主要用于描述被@Configuration注解的配置类的信息,我们在spring中定义的配置类,会被spring首先解析成BeanDefinition,然后spring会根据此BeanDefinition创建配置类对应的ConfigurationClass

如下类,spring会生成对应的ConfigurationClass模型

@Configuration
@Import({ SessionRouteConfig.class })
@EnableConfigurationProperties({ ServiceInstanceProperties.class, SessionProperties.class })
public class GatewayConfiguration {
    @Bean
    @ConditionalOnMissingBean
    SessionFilterPredicateFactory sessionFilterPredicateFactory() {
        return new DefaultSessionFilterPredicateFactory();
    }

}   
  • 配置类中被@Bean注解的方法模型BeanMethod
final class BeanMethod extends ConfigurationMethod {

    public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
        super(metadata, configurationClass);
    }

    @Override
    public void validate(ProblemReporter problemReporter) {
        if (getMetadata().isStatic()) {
            // static @Bean methods have no constraints to validate -> return immediately
            return;
        }

        if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
            if (!getMetadata().isOverridable()) {
                // instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
                problemReporter.error(new NonOverridableMethodError());
            }
        }
    }
}   

BeanMethod 用于描述配置类下被@Bean修饰的方法的模型,spring会BeanMethod 模型创建方法返回类的BeanDefinition,并将其注册到bean定义注册中心,以达到bean定义的加载注册,如上例中sessionFilterPredicateFactory方法,spring会生成对应的BeanMethod 模型与之对应。

java配置定义bean加载解析入口

 

// 类 ConfigurationClassPostProcessor 
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
        PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
    /**
     * 从注册表中的配置类派生进一步的bean定义。
     * Derive further bean definitions from the configuration classes in the registry.
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        //处理配置类的bean定义
        processConfigBeanDefinitions(registry);
    }
    /**
     * Build and validate a configuration model based on the registry of
     * {@link Configuration} classes.
     */
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        //存在配置类bean定义的集合,用于存储所有被@Configuration注解的类
        List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
        //获取bean定义注册中心的bean定义名称集合
        String[] candidateNames = registry.getBeanDefinitionNames();

        for (String beanName : candidateNames) {
            //遍历名称根据名称在注册中心获取当前名称的BeanDefinition
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);

            //校验当前bean定义是否为配置类
            //判断当前的bean定义是否为存在精简或者完整的配置类标识,当存在此标识时标识已被处理过
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                    ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                //检测bean定义是否已经被处理
                if (logger.isDebugEnabled()) {
                    logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                }
            }
            //检测给定的bean定义是否是描述的配置类
            else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                //将配置类的bean定义添加到configCandidates
                configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
            }
        }

        //配置类bean定义的集合为空时不做任何处理直接返回
        // Return immediately if no @Configuration classes were found
        if (configCandidates.isEmpty()) {
            return;
        }

        //配置类bean定义的集合 排序
        // Sort by previously determined @Order value, if applicable
        configCandidates.sort((bd1, bd2) -> {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return Integer.compare(i1, i2);
        });

        //检测获取命名生成策略器
        // Detect any custom bean name generation strategy supplied through the enclosing application context
        SingletonBeanRegistry sbr = null;
        if (registry instanceof SingletonBeanRegistry) {
            sbr = (SingletonBeanRegistry) registry;
            if (!this.localBeanNameGeneratorSet) {
                BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
                if (generator != null) {
                    this.componentScanBeanNameGenerator = generator;
                    this.importBeanNameGenerator = generator;
                }
            }
        }

        if (this.environment == null) {
            this.environment = new StandardEnvironment();
        }

        //创建配置类的解析器,解析每个@Configuration注解的类
        // Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

        //准备解析的bean定义集合
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
        //处理完成的模型的集合
        Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
        do {
            //解析bean定义,生成ConfigurationClass模型
            parser.parse(candidates);
            //校验ConfigurationClass模型
            parser.validate();

            //获取解析到的ConfigurationClass模型集合
            Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
            //当前处理的模型中移除已经处理的的模型
            configClasses.removeAll(alreadyParsed);

            //读取模型并根据内容创建bean定义
            // Read the model and create bean definitions based on its content
            if (this.reader == null) {
                this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
            }
            //加载创建模型中的所有bean定义
            this.reader.loadBeanDefinitions(configClasses);
            //当前模型集合添加到已处理集合中
            alreadyParsed.addAll(configClasses);

            candidates.clear();
            //判断注册中心中注册表是否存在新增数据,如果有新增数据,重新遍历获取新增数据解析
            if (registry.getBeanDefinitionCount() > candidateNames.length) {
                String[] newCandidateNames = registry.getBeanDefinitionNames();
                Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
                Set<String> alreadyParsedClasses = new HashSet<>();
                for (ConfigurationClass configurationClass : alreadyParsed) {
                    alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
                }
                for (String candidateName : newCandidateNames) {
                    if (!oldCandidateNames.contains(candidateName)) {
                        BeanDefinition bd = registry.getBeanDefinition(candidateName);
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                                !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                            candidates.add(new BeanDefinitionHolder(bd, candidateName));
                        }
                    }
                }
                candidateNames = newCandidateNames;
            }
        }
        while (!candidates.isEmpty());
    }

}

类 ConfigurationClassPostProcessor 为spring对@Configuration解析处理的后置处理器。

  • ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,此接口是BeanFactoryPostProcessor的扩展接口,在BeanFactoryPostProcessor执行流程笔记中分析过,允许在正常的BeanFactoryPostProcessor执行检测开始之前注册更多的自定义bean。也就是说BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry可以在后置处理器执行前自定义注册更多的BeanDefinition

ConfigurationClassPostProcessor 的postProcessBeanDefinitionRegistry方法完成的功能如下:

  1. 遍历bean定义注册器中所有的bean定义查找配置bean定义(元数据中含有@Configuration注解的bean定义)
  2. 通过配置类解析器ConfigurationClassParser 根据配置bean定义创建配置模型ConfigurationClass和BeanMethod

 

    //解析bean定义,生成ConfigurationClass模型
    parser.parse(candidates);
    //校验ConfigurationClass模型
    parser.validate();
  1. 根据配置类模型转换器ConfigurationClassBeanDefinitionReader根据配置类模型创建配置类中的BeanDefinition并注册到BeanDefinition注册中心

 

    //读取模型并根据内容创建bean定义
    // Read the model and create bean definitions based on its content
    if (this.reader == null) {
        this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
    }
    //加载创建模型中的所有bean定义
    this.reader.loadBeanDefinitions(configClasses);

配置类解析器ConfigurationClassParser

配置类解析器ConfigurationClassParser 根据配置类的BeanDefinition生成配置类模型数据ConfigurationClass与BeanMethod

解析主方法parse

 

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<>();

        for (BeanDefinitionHolder holder : configCandidates) {
            //循环遍历配置类的bean定义,解析生成对应的ConfigurationClass模型
            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);
            }
        }

        processDeferredImportSelectors();
    }

此方法最终调用doProcessConfigurationClass方法对ConfigurationClass创建初始化

 

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
            throws IOException {

        // 递归处理配置类的成员嵌套类
        processMemberClasses(configClass, sourceClass);

        //处理配置类上的@PropertySource注解
        for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), PropertySources.class,
                org.springframework.context.annotation.PropertySource.class)) {
            if (this.environment instanceof ConfigurableEnvironment) {
                processPropertySource(propertySource);
            }
            else {
            
            }
        }
        //处理配置类上的@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), 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注解的方法
        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;
    }

doProcessConfigurationClass 方法依次完成如下功能:

  • 递归处理配置类的成员嵌套类
  • 处理配置类上的@PropertySource注解
  • 处理配置类上的@ComponentScan注解
  • 处理配置类上的@Import注解
  • 处理配置类上的@ImportResource注解
  • 处理配置类里@Bean注解的方法
  • 处理接口上的默认方法
  • 处理配置类的父类,如果有的话

最后spring 通过ConfigurationClassParser类将一个配置类的bean定义,解析成完整的ConfigurationClass(配置数据模型)

配置类模型转换bean定义

ConfigurationClassBeanDefinitionReader 会根据配置类模型ConfigurationClass读取创建BeanDefinition,并将BeanDefinition注册到bean定义注册表中。

加载配置中的BeanDefinition入口loadBeanDefinitions方法:

 

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
        //遍历ConfigurationClass依次加载注册配置的bean定义
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }

loadBeanDefinitions 通过调用loadBeanDefinitionsForConfigurationClass加载注册bean定义

 

private void loadBeanDefinitionsForConfigurationClass(
            ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        if (configClass.isImported()) {
            //将ConfigurationClass本身的bean定义注册到注册中心
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            // 遍历BeanMethod
            //根据BeanMethod 创建bean定义,此方法根据配置类中被@Bean注解的方法生成bean定义
            //将生成的bean定义注册到注册中心
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }

        //加载来自ImportedResources的bean定义并注册
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        //加载来自Import的bean定义并注册
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

loadBeanDefinitionsForConfigurationClass 根据ConfigurationClass 创建其配置的bean定义,并将其注册到bean定义注册中心


接下来整体梳理下@Configuration配置的bean定义加载解析流程:

  1. 在spring完成基于注解配置bean定义的扫描注册后,通过后置处理器,获取到注册表中所有的bean定义。
  2. 遍历bean定义生成含有@Configuration注解的bean定义的集合。
  3. 根据配置类bean定义集合通过配置类解析器ConfigurationClassParser生成ConfigurationClass集合。
  4. 根据ConfigurationClass集合通过ConfigurationClassBeanDefinitionReader类加载注册配置里的bean定义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值