Spring5源码解析5-ConfigurationClassPostProcessor (上)

2022-10-14,,,

接上回,我们讲到了refresh()方法中的invokebeanfactorypostprocessors(beanfactory)方法主要在执行beanfactorypostprocessor和其子接口beandefinitionregistrypostprocessor的方法。

在创建annotationconfigapplicationcontext对象时spring就添加了一个非常重要的beanfactorypostprocessor接口实现类:configurationclasspostprocessor。注意,这里说的添加只是添加到容器的beandefinitionmap中,还没有创建真正的实例bean。

简单回顾一下configurationclasspostprocessor是在什么时候被添加到容器中的:在annotationconfigapplicationcontext的无参构造器中创建annotatedbeandefinitionreader对象时会向传入的beandefinitionregistry中注册解析注解配置类相关的processors的beandefinitionconfigurationclasspostprocessor就是在此处被添加到容器中的。


configurationclasspostprocessor

先看一些configurationclasspostprocessor的继承体系:

configurationclasspostprocessor实现了beandefinitionregistrypostprocessor接口,也就拥有了在spring容器启动时,往容器中注册beandefinition的能力。

我们知道,configurationclasspostprocessor#postprocessbeandefinitionregistry方法是在refresh();方法中的invokebeanfactorypostprocessors(beanfactory);中被执行的,下面我们就一起来看一下该方法。

configurationclasspostprocessor#postprocessbeandefinitionregistry

@override
public void postprocessbeandefinitionregistry(beandefinitionregistry registry) {
    int registryid = system.identityhashcode(registry);
    if (this.registriespostprocessed.contains(registryid)) {
        throw new illegalstateexception(
                "postprocessbeandefinitionregistry already called on this post-processor against " + registry);
    }
    if (this.factoriespostprocessed.contains(registryid)) {
        throw new illegalstateexception(
                "postprocessbeanfactory already called on this post-processor against " + registry);
    }
    this.registriespostprocessed.add(registryid);

    processconfigbeandefinitions(registry);
}

主要的逻辑在processconfigbeandefinitions(registry);中,点开源码

public void processconfigbeandefinitions(beandefinitionregistry registry) {
    list<beandefinitionholder> configcandidates = new arraylist<>();
    //获取所有的beandefinitionname
    string[] candidatenames = registry.getbeandefinitionnames();

    for (string beanname : candidatenames) {
        beandefinition beandef = registry.getbeandefinition(beanname);

        // https://docs.spring.io/spring/docs/5.1.8.release/spring-framework-reference/core.html#beans-java-basic-concepts
        // full @configuration vs “lite” @bean mode
        if (configurationclassutils.isfullconfigurationclass(beandef) ||
                configurationclassutils.isliteconfigurationclass(beandef)) {
            if (logger.isdebugenabled()) {
                logger.debug("bean definition has already been processed as a configuration class: " + beandef);
            }
        }

        // 校验是否为配置类
        // 配置类分为两种 full @configuration vs “lite” @bean mode
        // 校验之后在 beandefinition 中添加标志属性
        // 如果满足条件则加入到configcandidates
        else if (configurationclassutils.checkconfigurationclasscandidate(beandef, this.metadatareaderfactory)) {
            // 如果是配置类,就放到 configcandidates 变量中
            configcandidates.add(new beandefinitionholder(beandef, beanname));
        }
    }

    // return immediately if no @configuration classes were found
    if (configcandidates.isempty()) {
        return;
    }

    // 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;
    // 传入的 registry 是 defaultlistablebeanfactory
    if (registry instanceof singletonbeanregistry) {
        sbr = (singletonbeanregistry) registry;
        if (!this.localbeannamegeneratorset) {
            //获取自定义beannamegenerator,一般情况下为空
            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();
    }

    // parse each @configuration class
    // new configurationclassparser,用来解析 @configuration 类
    configurationclassparser parser = new configurationclassparser(
            this.metadatareaderfactory, this.problemreporter, this.environment,
            this.resourceloader, this.componentscanbeannamegenerator, registry);

    // 将 configcandidates 转成 set  candidates , 去重
    set<beandefinitionholder> candidates = new linkedhashset<>(configcandidates);
    set<configurationclass> alreadyparsed = new hashset<>(configcandidates.size());
    do {
        // 解析配置类
        parser.parse(candidates);
        parser.validate();

        set<configurationclass> configclasses = new linkedhashset<>(parser.getconfigurationclasses());
        configclasses.removeall(alreadyparsed);

        // 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());
        }
        // import类,@bean,@importresource 转化为 beandefinition
        this.reader.loadbeandefinitions(configclasses);
        alreadyparsed.addall(configclasses);

        candidates.clear();
        // 再获取一下容器中beandefinition的数据,如果发现数量增加了,说明有新的beandefinition被注册了
        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());

    // register the importregistry as a bean in order to support importaware @configuration classes
    if (sbr != null && !sbr.containssingleton(import_registry_bean_name)) {
        sbr.registersingleton(import_registry_bean_name, parser.getimportregistry());
    }

    if (this.metadatareaderfactory instanceof cachingmetadatareaderfactory) {
        // clear cache in externally provided metadatareaderfactory; this is a no-op
        // for a shared cache since it'll be cleared by the applicationcontext.
        ((cachingmetadatareaderfactory) this.metadatareaderfactory).clearcache();
    }
}

获取所有的beandefinitionnames,然后循环这个数组,判断其是否为配置类。

前5个是spring注册的内置processor,最后一个是传入给annotationconfigapplicationcontext的配置类appconfig.class

在spring中存在两种configurationclass,一种是fullconfigurationclass另一种是liteconfigurationclass。关于这两者的区别,可以参看笔者文章之前关于full @configuration 和 lite @bean mode的文章。

configurationclassutils#checkconfigurationclasscandidate方法内部就是在判断属于哪种配置类,并在beandefinition中标记判断结果。其具体的判断逻辑如下:

public static boolean isfullconfigurationcandidate(annotationmetadata metadata) {
    return metadata.isannotated(configuration.class.getname());
}
private static final set<string> candidateindicators = new hashset<>(8);

static {
    candidateindicators.add(component.class.getname());
    candidateindicators.add(componentscan.class.getname());
    candidateindicators.add(import.class.getname());
    candidateindicators.add(importresource.class.getname());
}

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?
    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;
    }
}

判断configcandidates变量中存放的

配置类是否为空,如果不为空,则对其进行排序。

创建configurationclassparser对象,用于解析@configuration类,完成包的扫描、beandefinition的注册。主要通过执行parser.parse(candidates);方法来完成。

执行parser.parse(candidates)方法前 :

执行parser.parse(candidates)方法后 :

解析完配置类之后,紧接着又执行了this.reader.loadbeandefinitions(configclasses);方法。这个方法主要是用来处理import类@bean@importresource注解。关于这两个方法的具体细节,我们下次再讲。

最后又加了入了对importaware接口支持所需要的bean。

// register the importregistry as a bean in order to support importaware @configuration classes
if (sbr != null && !sbr.containssingleton(import_registry_bean_name)) {
    sbr.registersingleton(import_registry_bean_name, parser.getimportregistry());
}

关于对importaware接口的使用,我们也下次再讲。


未完待续......

源码学习笔记:https://github.com/shenjianeng/spring-code-study

欢迎各位关注公众号,大家一起学习成长。

《Spring5源码解析5-ConfigurationClassPostProcessor (上).doc》

下载本文的Word格式文档,以方便收藏与打印。