欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring5源码解析6-ConfigurationClassParser 解析配置类

程序员文章站 2023-04-04 16:38:53
在`ConfigurationClassPostProcessor#processConfigBeanDefinitions`方法中创建了`ConfigurationClassParser`对象并调用其`parse`方法。该方法就是在负责解析配置类、扫描包、注册`BeanDefinition`,源码... ......

configurationclassparser

configurationclasspostprocessor#processconfigbeandefinitions方法中创建了configurationclassparser对象并调用其parse方法。该方法就是在负责解析配置类、扫描包、注册beandefinition,源码如下:

//configurationclassparser#parseset<beandefinitionholder>) 方法源码
public void parse(set<beandefinitionholder> configcandidates) {
    for (beandefinitionholder holder : configcandidates) {
        beandefinition bd = holder.getbeandefinition();
        try {
            // 根据不同的 beandefinition 实例对象 调用不同的 parse 方法
            // 底层其实都是在调用 org.springframework.context.annotation.configurationclassparser.processconfigurationclass
            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);
        }
    }

    //执行deferredimportselector
    this.deferredimportselectorhandler.process();
}

在该方法内部根据不同的beandefinition实例对象,调用了不同的parse方法,而这些parse方法底层,实际上都是调用了configurationclassparser#processconfigurationclass方法。

protected void processconfigurationclass(configurationclass configclass) throws ioexception {
    // 是否需要跳过 @conditional
    if (this.conditionevaluator.shouldskip(configclass.getmetadata(), configurationphase.parse_configuration)) {
        return;
    }

    // 第一次进入的时候, configurationclasses size = 0,existingclass 肯定为 null
    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);
        }
    }

    // recursively process the configuration class and its superclass hierarchy.
    sourceclass sourceclass = assourceclass(configclass);
    do {
        // 真正的做解析
        sourceclass = doprocessconfigurationclass(configclass, sourceclass);
    }
    while (sourceclass != null);

    this.configurationclasses.put(configclass, configclass);
}

方法传入的configurationclass对象是对配置类的封装。首先判断配置类上是否有@conditional注解,是否需要跳过解析该配置类。

然后,调用doprocessconfigurationclass(configclass, sourceclass);做真正的解析。其中,configclass是程序的配置类,而sourceclass是通过configclass创建的。

protected final sourceclass doprocessconfigurationclass(configurationclass configclass, sourceclass sourceclass)
        throws ioexception {

    // @configuration 继承了 @component
    if (configclass.getmetadata().isannotated(component.class.getname())) {
        // recursively process any member (nested) classes first
        // 递归处理内部类
        processmemberclasses(configclass, sourceclass);
    }

    // process any @propertysource annotations
    // 处理@propertysource
    // @propertysource注解用来加载properties文件
    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");
        }
    }

    // process any @componentscan annotations
    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();
                }
                //判断解析获取的 beandefinition 中 是否有配置类
                // 这里的配置类包括fullconfigurationclass和liteconfigurationclass
                // 也就是说只要有@configuration、@component、@componentscan、@import、@importresource和@bean中的其中一个注解
                if (configurationclassutils.checkconfigurationclasscandidate(bdcand, this.metadatareaderfactory)) {
                    //如果有配置类,递归调用,解析该配置类,这个if几乎都为true,这个方法几乎都要执行
                    parse(bdcand.getbeanclassname(), holder.getbeanname());
                }
            }
        }
    }

    // process any @import annotations
    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);
        }
    }

    // process individual @bean methods
    //处理单个@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();
        }
    }

    // no superclass -> processing is complete
    return null;
}

解析内部类

配置类上有@configuration注解,该注解继承 @component,if 判断为true,调用processmemberclasses方法,递归解析配置类中的内部类。

解析@propertysource注解

如果配置类上有@propertysource注解,则解析加载properties文件,并将属性添加到spring上下文中。((configurableenvironment) this.environment).getpropertysources().addfirstpropertysource(newsource);

处理@componentscan注解

获取配置类上的@componentscan注解,判断是否需要跳过。循环所有的componentscan,立即执行扫描。componentscanannotationparser#parse方法如下:

public set<beandefinitionholder> parse(annotationattributes componentscan, final string declaringclass) {
    // 创建 classpathbeandefinitionscanner
    // 在 annotationconfigapplicationcontext 的构造器中也创建了一个classpathbeandefinitionscanner
    // 这里证明了,执行扫描 scanner 不是构造器中的,而是这里创建的
    classpathbeandefinitionscanner scanner = new classpathbeandefinitionscanner(this.registry,
            componentscan.getboolean("usedefaultfilters"), this.environment, this.resourceloader);

    // @componentscan 中可以注册自定义的 beannamegenerator
    // 但是需要注意,通过源码可以明白,这里注册的自定义beannamegenerator 只对当前 scanner 有效
    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);
    }

    // @componentscan(basepackageclasses = xx.class)
    // 可以指定basepackageclasses, 只要是与是这几个类所在包及其子包,就可以被spring扫描
    // 经常会用一个空的类来作为basepackageclasses,默认取当前配置类所在包及其子包
    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);
        }
    });

    //执行扫描
    return scanner.doscan(stringutils.tostringarray(basepackages));
}

挑一些我觉得是重点的地方记录一下:

  1. parse方法中新创建了一个classpathbeandefinitionscanner对象,而在 annotationconfigapplicationcontext 的构造器中也创建了一个classpathbeandefinitionscanner对象,这里证实了在spring内部,真正执行扫描的不是annotationconfigapplicationcontext中的scanner。
  2. 通过源码可以了解到,在@componentscan中是可以注册自定义的 beannamegenerator的,而这个beannamegenerator只对当前scanner有效。也就是说,这个beannamegenerator只能影响通过该scanner扫描的路径下的bean的beanname生成规则。
  3. 最后调用scanner.doscan(stringutils.tostringarray(basepackages));方法执行真正的扫描,方法返回扫描获取到的beandefinition

检验获得的beandefinition中是否有配置类

检验扫描获得的beandefinition中是否有配置类,如果有配置类,这里的配置类包括fullconfigurationclass和liteconfigurationclass。(也就是说只要有@configuration@component@componentscan@import@importresource@bean中的其中一个注解),则递归调用parse方法,进行解析。

解析 @import 注解

processimports(configclass, sourceclass, getimports(sourceclass), true);

processimports方法负责对@import注解进行解析。configclass是配置类,sourceclass又是通过configclass创建的,getimports(sourceclass)sourceclass获取所有的@import注解信息,然后调用configurationclassparser#processimports

// configurationclassparser#processimports 源码
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 {
            // importcandidates是@import的封装
            // 循环importcandidates对import的内容进行分类
            for (sourceclass candidate : importcandidates) {
                // import导入实现importselector接口的类
                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);
                    //是否有实现相关aware接口,如果有,这调用相关方法
                    parserstrategyutils.invokeawaremethods(
                            selector, this.environment, this.resourceloader, this.registry);
                    // 延迟加载的importselector
                    if (selector instanceof deferredimportselector) {
                        //  延迟加载的importselector先放到list中,延迟加载
                        this.deferredimportselectorhandler.handle(configclass, (deferredimportselector) selector);
                    } else {
                        // 普通的importselector ,执行其selectimports方法,获取需要导入的类的全限定类名数组
                        string[] importclassnames = selector.selectimports(currentsourceclass.getmetadata());
                        collection<sourceclass> importsourceclasses = assourceclasses(importclassnames);
                        // 递归调用
                        processimports(configclass, currentsourceclass, importsourceclasses, false);
                    }
                    // 是否为importbeandefinitionregistrar
                } else if (candidate.isassignable(importbeandefinitionregistrar.class)) {
                    // 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);
                    // 添加到成员变量 org.springframework.context.annotation.configurationclass.importbeandefinitionregistrars 中
                    configclass.addimportbeandefinitionregistrar(registrar, currentsourceclass.getmetadata());
                } else {
                    // candidate class not an importselector or importbeandefinitionregistrar ->
                    // process it as an @configuration class
                    // 普通 @configuration class
                    this.importstack.registerimport(
                            currentsourceclass.getmetadata(), candidate.getmetadata().getclassname());
                    // 解析导入的@configuration class
                    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();
        }
    }
}

解析 @importresource 注解

@importresource注解可以导入xml配置文件。

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

@bean方法转化为beanmethod对象,添加到configurationclass#beanmethods集合中。

如果有父类,则解析父类

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();
    }
}

如果有父类则返回父类class对象,继续调用该方法。直到返回null,外层循环结束。

do {
    // 真正的做解析
    sourceclass = doprocessconfigurationclass(configclass, sourceclass);
}
while (sourceclass != null);

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

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

Spring5源码解析6-ConfigurationClassParser 解析配置类