当前位置: 移动技术网 > IT编程>开发语言>Java > Spring5源码解析6-ConfigurationClassParser 解析配置类

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

2019年10月18日  | 移动技术网IT编程  | 我要评论

haha365,容中尔甲的老婆,牛骨网

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

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

coder小黑

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网