Spring5源码解析6-ConfigurationClassParser 解析配置类
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)); }
挑一些我觉得是重点的地方记录一下:
-
parse
方法中新创建了一个classpathbeandefinitionscanner
对象,而在annotationconfigapplicationcontext
的构造器中也创建了一个classpathbeandefinitionscanner
对象,这里证实了在spring内部,真正执行扫描的不是annotationconfigapplicationcontext
中的scanner。 - 通过源码可以了解到,在
@componentscan
中是可以注册自定义的beannamegenerator
的,而这个beannamegenerator
只对当前scanner有效。也就是说,这个beannamegenerator
只能影响通过该scanner扫描的路径下的bean的beanname生成规则。 - 最后调用
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
欢迎关注公众号,大家一起学习成长。
上一篇: 015.Kubernetes二进制部署所有节点kubelet
下一篇: ASP.NET操作Excel
推荐阅读
-
spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
-
Java并发之ReentrantLock类源码解析
-
Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
-
spring5 源码深度解析-----ApplicationContext容器refresh过程
-
Mybaits 源码解析 (八)----- 全网最详细,没有之一:结果集 ResultSet 自动映射成实体类对象(上篇)
-
Spring5源码解析6-ConfigurationClassParser 解析配置类
-
Mybaits 源码解析 (三)----- Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
-
Mybaits 源码解析 (二)----- 根据配置文件创建SqlSessionFactory(Configuration的创建过程)
-
.NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入
-
Java集合类源码解析:LinkedHashMap