spring源码深度解析— IOC 之 默认标签解析(上)
概述
接前两篇文章 spring源码深度解析—spring的整体架构和环境搭建 和 spring源码深度解析— ioc 之 容器的基本实现
本文主要研究spring标签的解析,spring的标签中有默认标签和自定义标签,两者的解析有着很大的不同,这次重点说默认标签的解析过程。
默认标签的解析是在defaultbeandefinitiondocumentreader.parsedefaultelement函数中进行的,分别对4种不同的标签(import,alias,bean和beans)做了不同处理。我们先看下此函数的源码:
private void parsedefaultelement(element ele, beandefinitionparserdelegate delegate) { if (delegate.nodenameequals(ele, import_element)) { importbeandefinitionresource(ele); } else if (delegate.nodenameequals(ele, alias_element)) { processaliasregistration(ele); } else if (delegate.nodenameequals(ele, bean_element)) { processbeandefinition(ele, delegate); } else if (delegate.nodenameequals(ele, nested_beans_element)) { // recurse doregisterbeandefinitions(ele); } }
bean标签的解析及注册
在4中标签中对bean标签的解析最为复杂也最为重要,所以从此标签开始深入分析,如果能理解这个标签的解析过程,其他标签的解析就迎刃而解了。对于bean标签的解析用的是processbeandefinition函数,首先看看函数processbeandefinition(ele,delegate),其代码如下:
protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) { beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele); if (bdholder != null) { bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder); try { // register the final decorated instance. beandefinitionreaderutils.registerbeandefinition(bdholder, getreadercontext().getregistry()); } catch (beandefinitionstoreexception ex) { getreadercontext().error("failed to register bean definition with name '" + bdholder.getbeanname() + "'", ele, ex); } // send registration event. getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder)); } }
刚开始看这个函数体时一头雾水,没有以前的函数那样的清晰的逻辑,我们细致的理下逻辑,大致流程如下:
- 首先委托beandefinitiondelegate类的parsebeandefinitionelement方法进行元素的解析,返回beandefinitionholder类型的实例bdholder,经过这个方法后bdholder实例已经包含了我们配置文件中的各种属性了,例如class,name,id,alias等。
- 当返回的dbholder不为空的情况下若存在默认标签的子节点下再有自定义属性,还需要再次对自定义标签进行解析。
- 当解析完成后,需要对解析后的bdholder进行注册,注册过程委托给了beandefinitionreaderutils的registerbeandefinition方法。
- 最后发出响应事件,通知相关的监听器已经加载完这个bean了。
解析beandefinition
接下来我们就针对具体的方法进行分析,首先我们从元素解析及信息提取开始,也就是beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele),进入 beandefinitiondelegate 类的 parsebeandefinitionelement 方法。我们看下源码:
public beandefinitionholder parsebeandefinitionelement(element ele, @nullable beandefinition containingbean) { // 解析 id 属性 string id = ele.getattribute(id_attribute); // 解析 name 属性 string nameattr = ele.getattribute(name_attribute); // 分割 name 属性 list<string> aliases = new arraylist<>(); if (stringutils.haslength(nameattr)) { string[] namearr = stringutils.tokenizetostringarray(nameattr, multi_value_attribute_delimiters); aliases.addall(arrays.aslist(namearr)); } string beanname = id; if (!stringutils.hastext(beanname) && !aliases.isempty()) { beanname = aliases.remove(0); if (logger.isdebugenabled()) { logger.debug("no xml 'id' specified - using '" + beanname + "' as bean name and " + aliases + " as aliases"); } } // 检查 name 的唯一性 if (containingbean == null) { checknameuniqueness(beanname, aliases, ele); } // 解析 属性,构造 abstractbeandefinition abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean); if (beandefinition != null) { // 如果 beanname 不存在,则根据条件构造一个 beanname if (!stringutils.hastext(beanname)) { try { if (containingbean != null) { beanname = beandefinitionreaderutils.generatebeanname( beandefinition, this.readercontext.getregistry(), true); } else { beanname = this.readercontext.generatebeanname(beandefinition); string beanclassname = beandefinition.getbeanclassname(); if (beanclassname != null && beanname.startswith(beanclassname) && beanname.length() > beanclassname.length() && !this.readercontext.getregistry().isbeannameinuse(beanclassname)) { aliases.add(beanclassname); } } if (logger.isdebugenabled()) { logger.debug("neither xml 'id' nor 'name' specified - " + "using generated bean name [" + beanname + "]"); } } catch (exception ex) { error(ex.getmessage(), ele); return null; } } string[] aliasesarray = stringutils.tostringarray(aliases); // 封装 beandefinitionholder return new beandefinitionholder(beandefinition, beanname, aliasesarray); } return null; }
上述方法就是对默认标签解析的全过程了,我们分析下当前层完成的工作:
(1)提取元素中的id和name属性
(2)进一步解析其他所有属性并统一封装到genericbeandefinition类型的实例中
(3)如果检测到bean没有指定beanname,那么使用默认规则为此bean生成beanname。
(4)将获取到的信息封装到beandefinitionholder的实例中。
代码:abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);是用来对标签中的其他属性进行解析,我们详细看下源码:
public abstractbeandefinition parsebeandefinitionelement( element ele, string beanname, @nullable beandefinition containingbean) { this.parsestate.push(new beanentry(beanname)); string classname = null; //解析class属性 if (ele.hasattribute(class_attribute)) { classname = ele.getattribute(class_attribute).trim(); } string parent = null; //解析parent属性 if (ele.hasattribute(parent_attribute)) { parent = ele.getattribute(parent_attribute); } try { //创建用于承载属性的abstractbeandefinition类型的genericbeandefinition实例 abstractbeandefinition bd = createbeandefinition(classname, parent); //硬编码解析bean的各种属性 parsebeandefinitionattributes(ele, beanname, containingbean, bd); //设置description属性 bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element)); //解析元素 parsemetaelements(ele, bd); //解析lookup-method属性 parselookupoverridesubelements(ele, bd.getmethodoverrides()); //解析replace-method属性 parsereplacedmethodsubelements(ele, bd.getmethodoverrides()); //解析构造函数的参数 parseconstructorargelements(ele, bd); //解析properties子元素 parsepropertyelements(ele, bd); //解析qualifier子元素 parsequalifierelements(ele, bd); bd.setresource(this.readercontext.getresource()); bd.setsource(extractsource(ele)); return bd; } catch (classnotfoundexception ex) { error("bean class [" + classname + "] not found", ele, ex); } catch (noclassdeffounderror err) { error("class that bean class [" + classname + "] depends on not found", ele, err); } catch (throwable ex) { error("unexpected failure during bean definition parsing", ele, ex); } finally { this.parsestate.pop(); } return null; }
接下来我们一步步分析解析过程。
bean详细解析过程
创建用于承载属性的beandefinition
beandefinition是一个接口,在spring中此接口有三种实现:rootbeandefinition、childbeandefinition已经genericbeandefinition。而三种实现都继承了abstractbeandefinition,其中beandefinition是配置文件元素标签在容器中的内部表示形式。元素标签拥有class、scope、lazy-init等属性,beandefinition则提供了相应的beanclass、scope、lazyinit属性,beandefinition和<bean>中的属性一一对应。其中rootbeandefinition是最常用的实现类,他对应一般性的元素标签,genericbeandefinition是自2.5版本以后新加入的bean文件配置属性定义类,是一站式服务的。
在配置文件中可以定义父和字,父用rootbeandefinition表示,而子用childbeandefinition表示,而没有父的就使用rootbeandefinition表示。abstractbeandefinition对两者共同的类信息进行抽象。
spring通过beandefinition将配置文件中的配置信息转换为容器的内部表示,并将这些beandefinition注册到beandefinitionregistry中。spring容器的beandefinitionregistry就像是spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从beandefinitionresistry中读取配置信息。它们之间的关系如下图所示:
因此,要解析属性首先要创建用于承载属性的实例,也就是创建genericbeandefinition类型的实例。而代码createbeandefinition(classname,parent)的作用就是实现此功能。我们详细看下方法体,代码如下:
protected abstractbeandefinition createbeandefinition(@nullable string classname, @nullable string parentname) throws classnotfoundexception { return beandefinitionreaderutils.createbeandefinition( parentname, classname, this.readercontext.getbeanclassloader()); } public static abstractbeandefinition createbeandefinition( @nullable string parentname, @nullable string classname, @nullable classloader classloader) throws classnotfoundexception { genericbeandefinition bd = new genericbeandefinition(); bd.setparentname(parentname); if (classname != null) { if (classloader != null) { bd.setbeanclass(classutils.forname(classname, classloader)); } else { bd.setbeanclassname(classname); } } return bd; }
各种属性的解析
当创建好了承载bean信息的实例后,接下来就是解析各种属性了,首先我们看下parsebeandefinitionattributes(ele, beanname, containingbean, bd);方法,代码如下:
public abstractbeandefinition parsebeandefinitionattributes(element ele, string beanname, @nullable beandefinition containingbean, abstractbeandefinition bd) { //解析singleton属性 if (ele.hasattribute(singleton_attribute)) { error("old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } //解析scope属性 else if (ele.hasattribute(scope_attribute)) { bd.setscope(ele.getattribute(scope_attribute)); } else if (containingbean != null) { // take default from containing bean in case of an inner bean definition. bd.setscope(containingbean.getscope()); } //解析abstract属性 if (ele.hasattribute(abstract_attribute)) { bd.setabstract(true_value.equals(ele.getattribute(abstract_attribute))); } //解析lazy_init属性 string lazyinit = ele.getattribute(lazy_init_attribute); if (default_value.equals(lazyinit)) { lazyinit = this.defaults.getlazyinit(); } bd.setlazyinit(true_value.equals(lazyinit)); //解析autowire属性 string autowire = ele.getattribute(autowire_attribute); bd.setautowiremode(getautowiremode(autowire)); //解析dependson属性 if (ele.hasattribute(depends_on_attribute)) { string dependson = ele.getattribute(depends_on_attribute); bd.setdependson(stringutils.tokenizetostringarray(dependson, multi_value_attribute_delimiters)); } //解析autowirecandidate属性 string autowirecandidate = ele.getattribute(autowire_candidate_attribute); if ("".equals(autowirecandidate) || default_value.equals(autowirecandidate)) { string candidatepattern = this.defaults.getautowirecandidates(); if (candidatepattern != null) { string[] patterns = stringutils.commadelimitedlisttostringarray(candidatepattern); bd.setautowirecandidate(patternmatchutils.simplematch(patterns, beanname)); } } else { bd.setautowirecandidate(true_value.equals(autowirecandidate)); } //解析primary属性 if (ele.hasattribute(primary_attribute)) { bd.setprimary(true_value.equals(ele.getattribute(primary_attribute))); } //解析init_method属性 if (ele.hasattribute(init_method_attribute)) { string initmethodname = ele.getattribute(init_method_attribute); bd.setinitmethodname(initmethodname); } else if (this.defaults.getinitmethod() != null) { bd.setinitmethodname(this.defaults.getinitmethod()); bd.setenforceinitmethod(false); } //解析destroy_method属性 if (ele.hasattribute(destroy_method_attribute)) { string destroymethodname = ele.getattribute(destroy_method_attribute); bd.setdestroymethodname(destroymethodname); } else if (this.defaults.getdestroymethod() != null) { bd.setdestroymethodname(this.defaults.getdestroymethod()); bd.setenforcedestroymethod(false); } //解析factory_method属性 if (ele.hasattribute(factory_method_attribute)) { bd.setfactorymethodname(ele.getattribute(factory_method_attribute)); } //解析factory_bean属性 if (ele.hasattribute(factory_bean_attribute)) { bd.setfactorybeanname(ele.getattribute(factory_bean_attribute)); } return bd; }
解析meta元素
在开始对meta元素解析分析前我们先简单回顾下meta属性的使用,简单的示例代码如下:
<bean id="demo" class="com.yhl.myspring.demo.bean.mybeandemo"> <property name="beanname" value="bean demo1"/> <meta key="demo" value="demo"/> </bean>
这段代码并不会提现在demo的属性中,而是一个额外的声明,如果需要用到这里面的信息时可以通过beandefinition的getattribute(key)方法获取,对meta属性的解析用的是:parsemetaelements(ele, bd);具体的方法体如下:
public void parsemetaelements(element ele, beanmetadataattributeaccessor attributeaccessor) { nodelist nl = ele.getchildnodes(); for (int i = 0; i < nl.getlength(); i++) { node node = nl.item(i); if (iscandidateelement(node) && nodenameequals(node, meta_element)) { element metaelement = (element) node; string key = metaelement.getattribute(key_attribute); string value = metaelement.getattribute(value_attribute); beanmetadataattribute attribute = new beanmetadataattribute(key, value); attribute.setsource(extractsource(metaelement)); attributeaccessor.addmetadataattribute(attribute); } } }
解析replaced-method属性
在分析代码前我们还是先简单的了解下replaced-method的用法,其主要功能是方法替换:即在运行时用新的方法替换旧的方法。与之前的lookup-method不同的是此方法不仅可以替换返回的bean,还可以动态的更改原有方法的运行逻辑,我们看下使用:
//原有的changeme方法 public class testchangemethod { public void changeme() { system.out.println("changeme"); } } //新的实现方法 public class replacerchangemethod implements methodreplacer { public object reimplement(object o, method method, object[] objects) throws throwable { system.out.println("i replace method"); return null; } } //新的配置文件 <?xml version="1.0" encoding="utf-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="changeme" class="com.chenhao.spring.testchangemethod"> <replaced-method name="changeme" replacer="replacer"/> </bean> <bean id="replacer" class="com.chenhao.spring.replacerchangemethod"></bean> </beans> //测试方法 public class testdemo { public static void main(string[] args) { applicationcontext context = new classpathxmlapplicationcontext("replaced-method.xml"); testchangemethod test =(testchangemethod) context.getbean("changeme"); test.changeme(); } }
接下来我们看下解析replaced-method的方法代码:
public void parsereplacedmethodsubelements(element beanele, methodoverrides overrides) { nodelist nl = beanele.getchildnodes(); for (int i = 0; i < nl.getlength(); i++) { node node = nl.item(i); if (iscandidateelement(node) && nodenameequals(node, replaced_method_element)) { element replacedmethodele = (element) node; string name = replacedmethodele.getattribute(name_attribute); string callback = replacedmethodele.getattribute(replacer_attribute); replaceoverride replaceoverride = new replaceoverride(name, callback); // look for arg-type match elements. list<element> argtypeeles = domutils.getchildelementsbytagname(replacedmethodele, arg_type_element); for (element argtypeele : argtypeeles) { string match = argtypeele.getattribute(arg_type_match_attribute); match = (stringutils.hastext(match) ? match : domutils.gettextvalue(argtypeele)); if (stringutils.hastext(match)) { replaceoverride.addtypeidentifier(match); } } replaceoverride.setsource(extractsource(replacedmethodele)); overrides.addoverride(replaceoverride); } } }
我们可以看到无论是 look-up 还是 replaced-method 是构造了 methodoverride ,并最终记录在了 abstractbeandefinition 中的 methodoverrides 属性中
解析constructor-arg
对构造函数的解析式非常常用,也是非常复杂的,我们先从一个简单配置构造函数的例子开始分析,代码如下:
public void parseconstructorargelement(element ele, beandefinition bd) { //提前index属性 string indexattr = ele.getattribute(index_attribute); //提前type属性 string typeattr = ele.getattribute(type_attribute); //提取name属性 string nameattr = ele.getattribute(name_attribute); if (stringutils.haslength(indexattr)) { try { int index = integer.parseint(indexattr); if (index < 0) { error("'index' cannot be lower than 0", ele); } else { try { this.parsestate.push(new constructorargumententry(index)); //解析ele对应的元素属性 object value = parsepropertyvalue(ele, bd, null); constructorargumentvalues.valueholder valueholder = new constructorargumentvalues.valueholder(value); if (stringutils.haslength(typeattr)) { valueholder.settype(typeattr); } if (stringutils.haslength(nameattr)) { valueholder.setname(nameattr); } valueholder.setsource(extractsource(ele)); if (bd.getconstructorargumentvalues().hasindexedargumentvalue(index)) { error("ambiguous constructor-arg entries for index " + index, ele); } else { bd.getconstructorargumentvalues().addindexedargumentvalue(index, valueholder); } } finally { this.parsestate.pop(); } } } catch (numberformatexception ex) { error("attribute 'index' of tag 'constructor-arg' must be an integer", ele); } } else { try { this.parsestate.push(new constructorargumententry()); object value = parsepropertyvalue(ele, bd, null); constructorargumentvalues.valueholder valueholder = new constructorargumentvalues.valueholder(value); if (stringutils.haslength(typeattr)) { valueholder.settype(typeattr); } if (stringutils.haslength(nameattr)) { valueholder.setname(nameattr); } valueholder.setsource(extractsource(ele)); bd.getconstructorargumentvalues().addgenericargumentvalue(valueholder); } finally { this.parsestate.pop(); } } }
上述代码的流程可以简单的总结为如下:
(1)首先提取index、type、name等属性
(2)根据是否配置了index属性解析流程不同
如果配置了index属性,解析流程如下:
(1)使用parsepropertyvalue(ele, bd, null)方法读取constructor-arg的子元素
(2)使用constructorargumentvalues.valueholder封装解析出来的元素
(3)将index、type、name属性也封装进valueholder中,然后将valuehoder添加到当前beandefinition的constructorargumentvalues的indexedargumentvalues,而indexedargumentvalues是一个map类型
如果没有配置index属性,将index、type、name属性也封装进valueholder中,然后将valuehoder添加到当前beandefinition的constructorargumentvalues的genericargumentvalues中
public object parsepropertyvalue(element ele, beandefinition bd, @nullable string propertyname) { string elementname = (propertyname != null) ? "<property> element for property '" + propertyname + "'" : "<constructor-arg> element"; // should only have one child element: ref, value, list, etc. nodelist nl = ele.getchildnodes(); element subelement = null; for (int i = 0; i < nl.getlength(); i++) { node node = nl.item(i); //略过description和meta属性 if (node instanceof element && !nodenameequals(node, description_element) && !nodenameequals(node, meta_element)) { // child element is what we're looking for. if (subelement != null) { error(elementname + " must not contain more than one sub-element", ele); } else { subelement = (element) node; } } } //解析ref属性 boolean hasrefattribute = ele.hasattribute(ref_attribute); //解析value属性 boolean hasvalueattribute = ele.hasattribute(value_attribute); if ((hasrefattribute && hasvalueattribute) || ((hasrefattribute || hasvalueattribute) && subelement != null)) { error(elementname + " is only allowed to contain either 'ref' attribute or 'value' attribute or sub-element", ele); } if (hasrefattribute) { string refname = ele.getattribute(ref_attribute); if (!stringutils.hastext(refname)) { error(elementname + " contains empty 'ref' attribute", ele); } //使用runtimebeanreference来封装ref对应的bean runtimebeanreference ref = new runtimebeanreference(refname); ref.setsource(extractsource(ele)); return ref; } else if (hasvalueattribute) { //使用typedstringvalue 来封装value属性 typedstringvalue valueholder = new typedstringvalue(ele.getattribute(value_attribute)); valueholder.setsource(extractsource(ele)); return valueholder; } else if (subelement != null) { //解析子元素 return parsepropertysubelement(subelement, bd); } else { // neither child element nor "ref" or "value" attribute found. error(elementname + " must specify a ref or value", ele); return null; } }
上述代码的执行逻辑简单总结为:
(1)首先略过decription和meta属性
(2)提取constructor-arg上的ref和value属性,并验证是否存在
(3)存在ref属性时,用runtimebeanreference来封装ref
(4)存在value属性时,用typedstringvalue来封装
(5)存在子元素时,对于子元素的处理使用了方法parsepropertysubelement(subelement, bd);,其代码如下:
public object parsepropertysubelement(element ele, @nullable beandefinition bd) { return parsepropertysubelement(ele, bd, null); } public object parsepropertysubelement(element ele, @nullable beandefinition bd, @nullable string defaultvaluetype) { //判断是否是默认标签处理 if (!isdefaultnamespace(ele)) { return parsenestedcustomelement(ele, bd); } //对于bean标签的处理 else if (nodenameequals(ele, bean_element)) { beandefinitionholder nestedbd = parsebeandefinitionelement(ele, bd); if (nestedbd != null) { nestedbd = decoratebeandefinitionifrequired(ele, nestedbd, bd); } return nestedbd; } else if (nodenameequals(ele, ref_element)) { // a generic reference to any name of any bean. string refname = ele.getattribute(bean_ref_attribute); boolean toparent = false; if (!stringutils.haslength(refname)) { // a reference to the id of another bean in a parent context. refname = ele.getattribute(parent_ref_attribute); toparent = true; if (!stringutils.haslength(refname)) { error("'bean' or 'parent' is required for <ref> element", ele); return null; } } if (!stringutils.hastext(refname)) { error("<ref> element contains empty target attribute", ele); return null; } runtimebeanreference ref = new runtimebeanreference(refname, toparent); ref.setsource(extractsource(ele)); return ref; } //idref元素处理 else if (nodenameequals(ele, idref_element)) { return parseidrefelement(ele); } //value元素处理 else if (nodenameequals(ele, value_element)) { return parsevalueelement(ele, defaultvaluetype); } //null元素处理 else if (nodenameequals(ele, null_element)) { // it's a distinguished null value. let's wrap it in a typedstringvalue // object in order to preserve the source location. typedstringvalue nullholder = new typedstringvalue(null); nullholder.setsource(extractsource(ele)); return nullholder; } //array元素处理 else if (nodenameequals(ele, array_element)) { return parsearrayelement(ele, bd); } //list元素处理 else if (nodenameequals(ele, list_element)) { return parselistelement(ele, bd); } //set元素处理 else if (nodenameequals(ele, set_element)) { return parsesetelement(ele, bd); } //map元素处理 else if (nodenameequals(ele, map_element)) { return parsemapelement(ele, bd); } //props元素处理 else if (nodenameequals(ele, props_element)) { return parsepropselement(ele); } else { error("unknown property sub-element: [" + ele.getnodename() + "]", ele); return null; } }
解析子元素properties
对于propertie元素的解析是使用的parsepropertyelements(ele, bd);方法,我们看下其源码如下:
public void parsepropertyelements(element beanele, beandefinition bd) { nodelist nl = beanele.getchildnodes(); for (int i = 0; i < nl.getlength(); i++) { node node = nl.item(i); if (iscandidateelement(node) && nodenameequals(node, property_element)) { parsepropertyelement((element) node, bd); } } }
里面实际的解析是用的parsepropertyelement((element) node, bd);方法,继续跟踪代码:
public void parsepropertyelement(element ele, beandefinition bd) { string propertyname = ele.getattribute(name_attribute); if (!stringutils.haslength(propertyname)) { error("tag 'property' must have a 'name' attribute", ele); return; } this.parsestate.push(new propertyentry(propertyname)); try { //不允许多次对同一属性配置 if (bd.getpropertyvalues().contains(propertyname)) { error("multiple 'property' definitions for property '" + propertyname + "'", ele); return; } object val = parsepropertyvalue(ele, bd, propertyname); propertyvalue pv = new propertyvalue(propertyname, val); parsemetaelements(ele, pv); pv.setsource(extractsource(ele)); bd.getpropertyvalues().addpropertyvalue(pv); } finally { this.parsestate.pop(); } }
我们看到代码的逻辑非常简单,在获取了propertie的属性后使用propertyvalue 进行封装,然后将其添加到beandefinition的propertyvaluelist中
推荐博客
解析子元素 qualifier
对于 qualifier 元素的获取,我们接触更多的是注解的形式,在使用 spring 架中进行自动注入时,spring 器中匹配的候选 bean 数目必须有且仅有一个,当找不到一个匹配的 bean 时, spring容器将抛出 beancreationexception 异常, 并指出必须至少拥有一个匹配的 bean。
spring 允许我们通过qualifier 指定注入 bean的名称,这样歧义就消除了,而对于配置方式使用如:
<bean id="mytestbean" class="com.chenhao.spring.mytestbean">
<qualifier type="org.springframework.beans.factory.annotation.qualifier" value="gf" /> </bean>
其解析过程与之前大同小异 这里不再重复叙述
至此我们便完成了对 xml 文档到 genericbeandefinition 的转换, 就是说到这里, xml 中所有的配置都可以在 genericbeandefinition的实例类中应找到对应的配置。
genericbeandefinition 只是子类实现,而大部分的通用属性都保存在了 bstractbeandefinition 中,那么我们再次通过 abstractbeandefinition 的属性来回顾一 下我们都解析了哪些对应的配置。
public abstract class abstractbeandefinition extends beanmetadataattributeaccessor implements beandefinition, cloneable { // 此处省略静态变量以及final变量 @nullable private volatile object beanclass; /** * bean的作用范围,对应bean属性scope */ @nullable private string scope = scope_default; /** * 是否是抽象,对应bean属性abstract */ private boolean abstractflag = false; /** * 是否延迟加载,对应bean属性lazy-init */ private boolean lazyinit = false; /** * 自动注入模式,对应bean属性autowire */ private int autowiremode = autowire_no; /** * 依赖检查,spring 3.0后弃用这个属性 */ private int dependencycheck = dependency_check_none; /** * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on */ @nullable private string[] dependson; /** * autowire-candidate属性设置为false,这样容器在查找自动装配对象时, * 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者, * 但是该bean本身还是可以使用自动装配来注入其他bean的 */ private boolean autowirecandidate = true; /** * 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary */ private boolean primary = false; /** * 用于记录qualifier,对应子元素qualifier */ private final map<string, autowirecandidatequalifier> qualifiers = new linkedhashmap<>(0); @nullable private supplier<?> instancesupplier; /** * 允许访问非公开的构造器和方法,程序设置 */ private boolean nonpublicaccessallowed = true; /** * 是否以一种宽松的模式解析构造函数,默认为true, * 如果为false,则在以下情况 * interface itest{} * class itestimpl implements itest{}; * class main { * main(itest i) {} * main(itestimpl i) {} * } * 抛出异常,因为spring无法准确定位哪个构造函数程序设置 */ private boolean lenientconstructorresolution = true; /** * 对应bean属性factory-bean,用法: * <bean id = "instancefactorybean" class = "example.chapter3.instancefactorybean" /> * <bean id = "currenttime" factory-bean = "instancefactorybean" factory-method = "createtime" /> */ @nullable private string factorybeanname; /** * 对应bean属性factory-method */ @nullable private string factorymethodname; /** * 记录构造函数注入属性,对应bean属性constructor-arg */ @nullable private constructorargumentvalues constructorargumentvalues; /** * 普通属性集合 */ @nullable private mutablepropertyvalues propertyvalues; /** * 方法重写的持有者,记录lookup-method、replaced-method元素 */ @nullable private methodoverrides methodoverrides; /** * 初始化方法,对应bean属性init-method */ @nullable private string initmethodname; /** * 销毁方法,对应bean属性destroy-method */ @nullable private string destroymethodname; /** * 是否执行init-method,程序设置 */ private boolean enforceinitmethod = true; /** * 是否执行destroy-method,程序设置 */ private boolean enforcedestroymethod = true; /** * 是否是用户定义的而不是应用程序本身定义的,创建aop时候为true,程序设置 */ private boolean synthetic = false; /** * 定义这个bean的应用,application:用户,infrastructure:完全内部使用,与用户无关, * support:某些复杂配置的一部分 * 程序设置 */ private int role = beandefinition.role_application; /** * bean的描述信息 */ @nullable private string description; /** * 这个bean定义的资源 */ @nullable private resource resource; }
上一篇: Serverless
下一篇: 红牌
推荐阅读
-
spring源码深度解析— IOC 之 默认标签解析(上)
-
spring源码深度解析— IOC 之 循环依赖处理
-
【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
-
spring源码深度解析— IOC 之 开启 bean 的加载
-
spring源码深度解析— IOC 之 默认标签解析(下)
-
spring源码深度解析— IOC 之 bean 的初始化
-
【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
-
【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
-
spring源码深度解析— IOC 之 属性填充
-
spring源码深度解析— IOC 之 默认标签解析(上)