栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring配置类解析(上)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring配置类解析(上)

配置类解析

在《Spring容器启动(下)》中说到了,Spring启动过程中最核心的方法就是invokeBeanFactoryPostProcessors(),该方法会按照优先级去调用实现了BeanDefinitionRegistryPostProcessor接口和BeanFactoryPostProcessor接口的postProcessBeanDefinitionRegistry()和postProcessBeanFactory(),而这两个方法中,实现了配置类的扫描解析与增强,这篇文章将重点介绍配置类的扫描过程。

PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors()方法中,核心的两个方法是invokeBeanDefinitionRegistryPostProcessors()和invokeBeanFactoryPostProcessors(),这两个方法的源码如下

private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

   for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
      StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
            .tag("postProcessor", postProcessor::toString);
      postProcessor.postProcessBeanDefinitionRegistry(registry);
      postProcessBeanDefRegistry.end();
   }
}
private static void invokeBeanFactoryPostProcessors(
      Collection postProcessors, ConfigurableListableBeanFactory beanFactory) {

   for (BeanFactoryPostProcessor postProcessor : postProcessors) {
      StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
            .tag("postProcessor", postProcessor::toString);
      postProcessor.postProcessBeanFactory(beanFactory);
      postProcessBeanFactory.end();
   }
}

Spring中主要的解析配置类的方法是ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry(),而整个解析配置的核心逻辑在processConfigBeanDefinitions()中

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   int registryId = System.identityHashCode(registry);
   ……
   this.registriesPostProcessed.add(registryId);

   // 解析配置类
   processConfigBeanDefinitions(registry);
}
一、判断配置类

在解析配置类之前,首先需要判断是否该类是否是配置类,只有配置类才需要进行解析

首先获取当前容器中已经添加的BeanDefinitonName,由于此时还没有进行扫描,此时容器中的BeanDefinition只有容器启动时手动注册的配置类的BeanDefinition和Spring自己添加的一些常用的BeanPostProcessor的BeanDefinition,这些BeanDefinition在《Spring容器启动(上)》中有作说明

获取到这些BeanDefiniton后,会去判断是否是配置类,如果是配置类,就添加到configCandidates中,后续遍历解析

ConfigurationClassUtils的checkConfigurationClassCandidate()用于判断是否为配置类

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        // 什么是配置类?
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    ……
}
1.1 @Bean对应的类不能为配置类

假设有一个类A,满足属于配置类的条件,但是在类B中,通过@Bean定义了A的实例,那么类A将不能作为配置类处理,通过@Bean生成BeanDefiniton,它的beanClassName为null,或者factoryMethodName不为null

@configuration
Class A{
}

Class B{
    @Bean
    public A a(){
        return new A();
    }
}
public static boolean checkConfigurationClassCandidate(
    BeanDefinition beanDef, metadataReaderFactory metadataReaderFactory) {

    // @Bean定义的配置类Bean是不起作用的 
    String className = beanDef.getBeanClassName();
    if (className == null || beanDef.getFactoryMethodName() != null) {
        return false;
    }
	……
}
1.2 获取注解信息

获取该类的所有注解信息,后面会根据注解来判断该类是否为配置类

// Annotationmetadata表示某个类的注解信息,但是并一定要加载这个类
Annotationmetadata metadata;
//省略获取类注解信息的代码,会通过三种判断来获取注解信息
……
    metadataReader metadataReader = metadataReaderFactory.getmetadataReader(className);
metadata = metadataReader.getAnnotationmetadata();
1.3 判断@Configuration注解

如果一个类上加了@Configuration注解,它就是一个配置类,但该注解的proxyBeanMethods属性又将配置类分为Full和lite配置类,具体后面再介绍

Map config = metadata.getAnnotationAttributes(Configuration.class.getName());

// 存在@Configuration,并且proxyBeanMethods不为false(为true或为null)时,就是Full配置类
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
// 存在@Configuration,并且proxyBeanMethods为false时,是lite配置类
// 或者不存在@Configuration,但是只要存在@Component、@ComponentScan、@import、@importResource四个中的一个,就是lite配置类
// 或者不存在@Configuration,只要存在@Bean注解了的方法,就是lite配置类
else if (config != null || isConfigurationCandidate(metadata)) {
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
    return false;
}

如果该类没有添加@Configuration注解,则通过isConfigurationCandidate()判断是否为配置类

通过这种方式判断出来的配置类都属于lite类型

如果是一个接口,则不属于配置类;如果有Component、ComponentScan、import、importResource中的任一个注解,就是配置类;如果有@Bean定义的方法,就是一个配置类

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

    // Any of the typical annotations found?
    for (String indicator : candidateIndicators) {
        if (metadata.isAnnotated(indicator)) {
            return true;
        }
    }

    // Finally, let's look for @Bean methods...
    return hasBeanMethods(metadata);
}

static {
    candidateIndicators.add(Component.class.getName());
    candidateIndicators.add(ComponentScan.class.getName());
    candidateIndicators.add(import.class.getName());
    candidateIndicators.add(importResource.class.getName());
}
1.4 设置Order值

判断完是否为配置后,设置BeanDifinition的Order值,用于对配置类进行排序,按优先级进行解析

// It's a full or lite configuration candidate... Let's determine the order value, if any.
Integer order = getOrder(metadata);
if (order != null) {
    beanDef.setAttribute(ORDER_ATTRIBUTE, order);
}

return true;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/602534.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号