Spring源碼學習筆記(五)node
前言-- spring
最近花了些時間看了《Spring源碼深度解析》這本書,算是入門了Spring的源碼吧。打算寫下系列文章,回憶一下書的內容,總結代碼的運行流程。推薦那些和我同樣沒接觸過SSH框架源碼又想學習的,閱讀郝佳編著的《Spring源碼深度解析》這本書,會是個很好的入門緩存
寫下一句話,開篇不尷尬 ---- 上篇文章中梳理到 Spring 加載資源文件後開始解析 Bean, 如今咱們從兩個解析函數 parseDefaultElement() 和 parseCustomElement() 開始繼續回顧。app
解析默認標籤 parseDefaultElement()框架
先來看看 parseDefaultElement() 實現邏輯:ide
1 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { 2 if(delegate.nodeNameEquals(ele, "import")) { 3 //第一步: 處理 import 標籤 4 this.importBeanDefinitionResource(ele); 5 } else if(delegate.nodeNameEquals(ele, "alias")) { 6 //第二步: 處理 alias 標籤 7 this.processAliasRegistration(ele); 8 } else if(delegate.nodeNameEquals(ele, "bean")) { 9 //第三步: 處理 bean 標籤 =============== 重點 10 this.processBeanDefinition(ele, delegate); 11 } else if(delegate.nodeNameEquals(ele, "beans")) { 12 //第四步: 處理 beans 標籤 13 this.doRegisterBeanDefinitions(ele); 14 } 15 16 }
呵呵哈, 什麼都沒寫, 接着往下看, 一個個分析四中標籤的解析。函數
一:bean 標籤post
processBeanDefinition() 方法的邏輯:學習
1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 2 //第一步: BeanDefinitionHolder 類的封裝 3 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 4 if(bdHolder != null) { 5 //第二步: 自定義屬性的處理 6 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 7 8 try { 9 //第三步; 註冊 bean 10 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); 11 } catch (BeanDefinitionStoreException var5) { 12 this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5); 13 } 14 //第四步: 發佈事件 15 this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 16 } 17 18 }
首先看第一步中, BeanDefinitionParserDelegate 類的 parseBeanDefinitionElement() 方法:ui
1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { 2 return this.parseBeanDefinitionElement(ele, (BeanDefinition)null); 3 }
1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { 2 //第一步: 解析 id 和 name 屬性 3 String id = ele.getAttribute("id"); 4 String nameAttr = ele.getAttribute("name"); 5 List<String> aliases = new ArrayList(); 6 if(StringUtils.hasLength(nameAttr)) { 7 //第二步: 分割了 name 屬性 8 String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; "); 9 aliases.addAll(Arrays.asList(nameArr)); 10 } 11 12 String beanName = id; 13 if(!StringUtils.hasText(id) && !aliases.isEmpty()) { 14 beanName = (String)aliases.remove(0); 15 16 } 17 18 if(containingBean == null) { 19 this.checkNameUniqueness(beanName, aliases, ele); 20 } 21 //第三步: 解析屬性, 封裝到 GenericBeanDefinition 類中 22 AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean); 23 if(beanDefinition != null) { 24 //第四步: 沒有指定 beanName , 生成 beanName 25 if(!StringUtils.hasText(beanName)) { 26 try { 27 if(containingBean != null) { 28 beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); 29 } else { 30 beanName = this.readerContext.generateBeanName(beanDefinition); 31 String beanClassName = beanDefinition.getBeanClassName(); 32 if(beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { 33 aliases.add(beanClassName); 34 } 35 } 36 } catch (Exception var9) { 37 this.error(var9.getMessage(), ele); 38 return null; 39 } 40 } 41 42 String[] aliasesArray = StringUtils.toStringArray(aliases); 43 //第五步: beanDefinition 封裝到 BeanDefinitionHolder中 44 return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); 45 } else { 46 return null; 47 } 48 }
在 parseBeanDefinitionElement() 方法中, 主要的是第二步解析屬性 parseBeanDefinitionElement() 方法:
1 public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) { 2 this.parseState.push(new BeanEntry(beanName)); 3 String className = null; 4 if(ele.hasAttribute("class")) { 5 //第一步: 解析 class 屬性 6 className = ele.getAttribute("class").trim(); 7 } 8 9 try { 10 String parent = null; 11 if(ele.hasAttribute("parent")) { 12 parent = ele.getAttribute("parent"); 13 } 14 //第二步: 封裝 AbstractBeanDefinition 的 GenericBeanDefinition 15 AbstractBeanDefinition bd = this.createBeanDefinition(className, parent); 16 this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); /** 解析屬性 */ 17 //第三步: 設置 description 屬性 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description")); 18 //第四步: 解析 元數據 19 this.parseMetaElements(ele, bd); 20 //第五步: 解析 lookup-method 屬性 21 this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); 22 //第六步: 解析 replaced-method 屬性 23 this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); 24 //第七步: 解析 構造函數 參數 25 this.parseConstructorArgElements(ele, bd); 26 //第八步: 解析 property 元素 27 this.parsePropertyElements(ele, bd); 28 //第九步: 解析 qualifier 元素 29 this.parseQualifierElements(ele, bd); 30 bd.setResource(this.readerContext.getResource()); 31 bd.setSource(this.extractSource(ele)); 32 AbstractBeanDefinition var7 = bd; 33 return var7; 34 } 35 /** 省略了 catch 語句 */ 36 finally { 37 this.parseState.pop(); 38 } 39 40 return null; 41 }
接下來詳細說明 parseBeanDefinitionElement() 方法的步驟, 由於不少, 開一個新行,雖然不少, 可是整體的思路仍是很清晰的, 就一類元素有對應的解析的方法, 不要亂了陣腳, 戰略上藐視一下。 o(* ̄︶ ̄*)o
parseBeanDefinitionElement() 中的方法 :
(一) createBeanDefinition()
首先了解一下各類 BeanDefinition 之間的關係:
XML 文件當中的 <bean> 解析以後, 封裝成 BeanDefinition 對象, 並註冊到 BeanDefinitionRegistry 類中, 主要以 map 的方式保存, 併爲後續的操做所使用。
而後在來看看 createBeanDefinition() 方法的實現邏輯:
1 protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { 2 return BeanDefinitionReaderUtils.createBeanDefinition(parentName, className, this.readerContext.getBeanClassLoader()); 3 }
1 public static AbstractBeanDefinition createBeanDefinition(String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { 2 //第一步: 封裝的 GenericBeanDefinition 實例 3 GenericBeanDefinition bd = new GenericBeanDefinition(); 4 bd.setParentName(parentName); 5 if(className != null) { 6 if(classLoader != null) { 7 //第二步: 存在 classLoader ,則反射建立實例 8 bd.setBeanClass(ClassUtils.forName(className, classLoader)); 9 } else { 10 //第三步: 不存在 clasLoader ,只能記錄一下 name 了 11 bd.setBeanClassName(className); 12 } 13 } 14 15 return bd; 16 }
(二) parseBeanDefinitionAttributes()
對 element 的屬性進行解析的實現邏輯:
1 public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { 2 //第一步: 解析 scope 屬性 3 if(ele.hasAttribute("scope")) { 4 bd.setScope(ele.getAttribute("scope")); 5 } else if(containingBean != null) { 6 bd.setScope(containingBean.getScope()); 7 } 8 //第二步: 解析 abstract 屬性 9 if(ele.hasAttribute("abstract")) { 10 bd.setAbstract("true".equals(ele.getAttribute("abstract"))); 11 } 12 //第三步: 解析 lazy-init 屬性 13 String lazyInit = ele.getAttribute("lazy-init"); 14 if("default".equals(lazyInit)) { 15 lazyInit = this.defaults.getLazyInit(); 16 } 17 18 bd.setLazyInit("true".equals(lazyInit)); 19 //第四步: 解析 autowire 屬性 20 String autowire = ele.getAttribute("autowire"); 21 bd.setAutowireMode(this.getAutowireMode(autowire)); 22 //第五步: 解析 dependency-check 屬性 23 String dependencyCheck = ele.getAttribute("dependency-check"); 24 bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck)); 25 //第六步: 解析 depends-on 屬性 26 String autowireCandidate; 27 if(ele.hasAttribute("depends-on")) { 28 autowireCandidate = ele.getAttribute("depends-on"); 29 bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; ")); 30 } 31 //第七步: 解析 autowire-candidate 屬性 32 autowireCandidate = ele.getAttribute("autowire-candidate"); 33 String destroyMethodName; 34 if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) { 35 bd.setAutowireCandidate("true".equals(autowireCandidate)); 36 } else { 37 destroyMethodName = this.defaults.getAutowireCandidates(); 38 if(destroyMethodName != null) { 39 String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName); 40 bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName)); 41 } 42 } 43 //第八步: 解析 primary 屬性 44 if(ele.hasAttribute("primary")) { 45 bd.setPrimary("true".equals(ele.getAttribute("primary"))); 46 } 47 //第九步: 解析 init-method 屬性 48 if(ele.hasAttribute("init-method")) { 49 destroyMethodName = ele.getAttribute("init-method"); 50 if(!"".equals(destroyMethodName)) { 51 bd.setInitMethodName(destroyMethodName); 52 } 53 } else if(this.defaults.getInitMethod() != null) { 54 bd.setInitMethodName(this.defaults.getInitMethod()); 55 bd.setEnforceInitMethod(false); 56 } 57 //第十步: 解析 destroy-method 屬性 58 if(ele.hasAttribute("destroy-method")) { 59 destroyMethodName = ele.getAttribute("destroy-method"); 60 if(!"".equals(destroyMethodName)) { 61 bd.setDestroyMethodName(destroyMethodName); 62 } 63 } else if(this.defaults.getDestroyMethod() != null) { 64 bd.setDestroyMethodName(this.defaults.getDestroyMethod()); 65 bd.setEnforceDestroyMethod(false); 66 } 67 //第十一步: 解析 destroy-method 屬性 68 if(ele.hasAttribute("factory-method")) { 69 bd.setFactoryMethodName(ele.getAttribute("factory-method")); 70 } 71 //第十二步: 解析 factory-bean 屬性 72 if(ele.hasAttribute("factory-bean")) { 73 bd.setFactoryBeanName(ele.getAttribute("factory-bean")); 74 } 75 76 return bd; 77 }
怎麼說呢, 天啦嚕,一大坨的代碼, 然而只是解析了各類各樣的屬性, 並設置到第一步中建立的 AbstractBeanDefinition 當中。
(三) parseMetaElements()
1 public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { 2 NodeList nl = ele.getChildNodes(); 3 //第一步: 遍歷全部的子元素 4 for(int i = 0; i < nl.getLength(); ++i) { 5 Node node = nl.item(i); 6 //第二步: 判斷元素的類型 7 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) { 8 Element metaElement = (Element)node; 9 String key = metaElement.getAttribute("key"); 10 String value = metaElement.getAttribute("value"); 11 //第三步: 構造 BeanMetadataAttribute 類 12 BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); 13 attribute.setSource(this.extractSource(metaElement)); 14 attributeAccessor.addMetadataAttribute(attribute); 15 } 16 } 17 18 }
(四) parseLookupOverrideSubElements() , parseReplacedMethodSubElements()
lookup-method 以及 replaced-method 屬性的使用請有事找度娘!!!o(^▽^)o
1 public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { 2 NodeList nl = beanEle.getChildNodes(); 3 //第一步: 遍歷子元素 4 for(int i = 0; i < nl.getLength(); ++i) { 5 Node node = nl.item(i); 6 //第二步: 判斷元素的類型 7 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) { 8 Element ele = (Element)node; 9 //第三步: 獲取重寫的方法 10 String methodName = ele.getAttribute("name"); 11 String beanRef = ele.getAttribute("bean"); 12 //第四步: 封裝爲 LookupOverride 類 13 LookupOverride override = new LookupOverride(methodName, beanRef); 14 override.setSource(this.extractSource(ele)); 15 overrides.addOverride(override); 16 } 17 } 18 19 }
1 public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { 2 NodeList nl = beanEle.getChildNodes(); 3 //第一步: 遍歷子元素 4 for(int i = 0; i < nl.getLength(); ++i) { 5 Node node = nl.item(i); 6 //第二步: 判斷夙願類型 7 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) { 8 //第三步: 獲取 要替換的方法 和 替換的方法 9 Element replacedMethodEle = (Element)node; 10 String name = replacedMethodEle.getAttribute("name"); 11 String callback = replacedMethodEle.getAttribute("replacer"); 12 //第四步: 封裝成 ReplaceOverride 類 13 ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); 14 //第五步: 方法的參數 15 List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type"); 16 Iterator var11 = argTypeEles.iterator(); 17 18 while(var11.hasNext()) { 19 Element argTypeEle = (Element)var11.next(); 20 String match = argTypeEle.getAttribute("match"); 21 match = StringUtils.hasText(match)?match:DomUtils.getTextValue(argTypeEle); 22 if(StringUtils.hasText(match)) { 23 replaceOverride.addTypeIdentifier(match); 24 } 25 } 26 27 replaceOverride.setSource(this.extractSource(replacedMethodEle)); 28 overrides.addOverride(replaceOverride); 29 } 30 } 31 32 }
(五) parseConstructorArgElements()
解析構造函數參數的實現邏輯:
1 public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) { 2 NodeList nl = beanEle.getChildNodes(); 3 //第一步: 遍歷全部元素 4 for(int i = 0; i < nl.getLength(); ++i) { 5 Node node = nl.item(i); 6 //第二步: 判斷元素類型 7 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) { 8 //第三步: 解析構造函數參數 9 this.parseConstructorArgElement((Element)node, bd); 10 } 11 } 12 13 }
前方高能~~~~~ 一大波代碼正在來襲!!!
1 public void parseConstructorArgElement(Element ele, BeanDefinition bd) { 2 //第一步: 提取 index, type, name 屬性 3 String indexAttr = ele.getAttribute("index"); 4 String typeAttr = ele.getAttribute("type"); 5 String nameAttr = ele.getAttribute("name"); 6 if(StringUtils.hasLength(indexAttr)) { 7 try { 8 int index = Integer.parseInt(indexAttr); 9 if(index < 0) { 10 this.error("'index' cannot be lower than 0", ele); 11 } else { 12 try { 13 this.parseState.push(new ConstructorArgumentEntry(index)); 14 //第二步: 解析 ele 對應的屬性元素 15 Object value = this.parsePropertyValue(ele, bd, (String)null); 16 //第四步: 封裝到 ValueHolder 類中 17 ValueHolder valueHolder = new ValueHolder(value); 18 if(StringUtils.hasLength(typeAttr)) { 19 valueHolder.setType(typeAttr); 20 } 21 22 if(StringUtils.hasLength(nameAttr)) { 23 valueHolder.setName(nameAttr); 24 } 25 26 valueHolder.setSource(this.extractSource(ele)); 27 //第五步: 相同參數重複指定的狀況處理 28 if(bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) { 29 this.error("Ambiguous constructor-arg entries for index " + index, ele); 30 } else { 31 //第六步: 存在 index 屬性的狀況時, 封裝到 BeanDefinition 的 constructorArgumentValues 的 indexedArgumentValue 中 32 bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder); 33 } 34 } finally { 35 this.parseState.pop(); 36 } 37 } 38 } catch (NumberFormatException var19) { 39 this.error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele); 40 } 41 } else { 42 try { 43 this.parseState.push(new ConstructorArgumentEntry()); 44 Object value = this.parsePropertyValue(ele, bd, (String)null); 45 ValueHolder valueHolder = new ValueHolder(value); 46 if(StringUtils.hasLength(typeAttr)) { 47 valueHolder.setType(typeAttr); 48 } 49 50 if(StringUtils.hasLength(nameAttr)) { 51 valueHolder.setName(nameAttr); 52 } 53 54 valueHolder.setSource(this.extractSource(ele)); 55 //第七步: 不存在 index 屬性時, 封裝到 BeanDefinition 的 constructorArgumentValues 的 genericArgumentValue 中 56 57 bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder); 58 } finally { 59 this.parseState.pop(); 60 } 61 } 62 63 }
(六) parsePropertyValue()
解析構造函數配置中子元素的實現邏輯, 感受就是上一步代碼沒作完的事堆給下一個方法收拾了(*/ω╲*)
1 public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { 2 String elementName = propertyName != null?"<property> element for property '" + propertyName + "'":"<constructor-arg> element"; 3 NodeList nl = ele.getChildNodes(); 4 Element subElement = null; 5 //第一步: 遍歷全部的子元素 6 for(int i = 0; i < nl.getLength(); ++i) { 7 Node node = nl.item(i); 8 //第二步: 略過 description 和 meta 9 if(node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) { 10 if(subElement != null) { 11 this.error(elementName + " must not contain more than one sub-element", ele); 12 } else { 13 subElement = (Element)node; 14 } 15 } 16 } 17 //第三步: 解析 constructor-arg 上的 ref 和 value 屬性 (!! 注意: 不存在 1,既有 ref 又有 vlaue 屬性 2,存在 ref 或 value 且還有子元素) 18 boolean hasRefAttribute = ele.hasAttribute("ref"); 19 boolean hasValueAttribute = ele.hasAttribute("value"); 20 if(hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) { 21 this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele); 22 } 23 24 if(hasRefAttribute) { 25 String refName = ele.getAttribute("ref"); 26 if(!StringUtils.hasText(refName)) { 27 this.error(elementName + " contains empty 'ref' attribute", ele); 28 } 29 //第四步: ref 屬性使用 RuntimeBeanReference 處理 30 RuntimeBeanReference ref = new RuntimeBeanReference(refName); 31 ref.setSource(this.extractSource(ele)); 32 return ref; 33 } else if(hasValueAttribute) { 34 //第五步: value 屬性使用 TypedStringValue 處理 35 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value")); 36 valueHolder.setSource(this.extractSource(ele)); 37 return valueHolder; 38 } else if(subElement != null) { 39 //第六步: 解析子元素 40 return this.parsePropertySubElement(subElement, bd); 41 } else { 42 this.error(elementName + " must specify a ref or value", ele); 43 return null; 44 } 45 }
在 parsePropertyValue() 中, 第六步解析子元素 parsePropertySubElement() 方法的實現:
1 public Object parsePropertySubElement(Element ele, BeanDefinition bd) { 2 return this.parsePropertySubElement(ele, bd, (String)null); 3 }
1 public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) { 2 //第一步: 不是默認命名空間的元素的處理 3 if(!this.isDefaultNamespace((Node)ele)) { 4 return this.parseNestedCustomElement(ele, bd); 5 } else if(this.nodeNameEquals(ele, "bean")) { 6 //第二步: 對 Bean 元素的處理 7 BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd); 8 if(nestedBd != null) { 9 nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd); 10 } 11 12 return nestedBd; 13 } else if(this.nodeNameEquals(ele, "ref")) { 14 //第三步: 對 ref 屬性的處理 15 String refName = ele.getAttribute("bean"); 16 boolean toParent = false; 17 if(!StringUtils.hasLength(refName)) { 18 refName = ele.getAttribute("local"); 19 if(!StringUtils.hasLength(refName)) { 20 refName = ele.getAttribute("parent"); 21 toParent = true; 22 if(!StringUtils.hasLength(refName)) { 23 this.error("'bean', 'local' or 'parent' is required for <ref> element", ele); 24 return null; 25 } 26 } 27 } 28 29 if(!StringUtils.hasText(refName)) { 30 this.error("<ref> element contains empty target attribute", ele); 31 return null; 32 } else { 33 RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent); 34 ref.setSource(this.extractSource(ele)); 35 return ref; 36 } 37 } else if(this.nodeNameEquals(ele, "idref")) { 38 //第四步: 對 idref 屬性的處理 39 return this.parseIdRefElement(ele); 40 } else if(this.nodeNameEquals(ele, "value")) { 41 //第五步: 對 value 屬性的處理 42 return this.parseValueElement(ele, defaultValueType); 43 } else if(this.nodeNameEquals(ele, "null")) { 44 //第六步: 對 null 元素的解析 45 TypedStringValue nullHolder = new TypedStringValue((String)null); 46 nullHolder.setSource(this.extractSource(ele)); 47 return nullHolder; 48 } 49 //第七步: 對各類集合屬性的解析 50 else if(this.nodeNameEquals(ele, "array")) { 51 return this.parseArrayElement(ele, bd); 52 } else if(this.nodeNameEquals(ele, "list")) { 53 return this.parseListElement(ele, bd); 54 } else if(this.nodeNameEquals(ele, "set")) { 55 return this.parseSetElement(ele, bd); 56 } else if(this.nodeNameEquals(ele, "map")) { 57 return this.parseMapElement(ele, bd); 58 } else if(this.nodeNameEquals(ele, "props")) { 59 return this.parsePropsElement(ele); 60 } else { 61 this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele); 62 return null; 63 } 64 }
(七) parsePropertyElements()
解析 <property> 元素的實現邏輯:
1 public void parsePropertyElements(Element beanEle, BeanDefinition bd) { 2 NodeList nl = beanEle.getChildNodes(); 3 //第一步: 遍歷全部的屬性 4 for(int i = 0; i < nl.getLength(); ++i) { 5 Node node = nl.item(i); 6 //第二步: 判斷元素的類型 7 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "property")) { 8 this.parsePropertyElement((Element)node, bd); 9 } 10 } 11 12 }
1 public void parsePropertyElement(Element ele, BeanDefinition bd) { 2 //第一步: 獲取 name 屬性 3 String propertyName = ele.getAttribute("name"); 4 if(!StringUtils.hasLength(propertyName)) { 5 this.error("Tag 'property' must have a 'name' attribute", ele); 6 } else { 7 this.parseState.push(new PropertyEntry(propertyName)); 8 9 try { 10 //第二步: 處理同一屬性屢次配置的狀況 11 if(bd.getPropertyValues().contains(propertyName)) { 12 this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele); 13 return; 14 } 15 //第三步: 解析元素屬性 16 Object val = this.parsePropertyValue(ele, bd, propertyName); 17 PropertyValue pv = new PropertyValue(propertyName, val); 18 this.parseMetaElements(ele, pv); 19 pv.setSource(this.extractSource(ele)); 20 //第四步: 添加屬性 21 bd.getPropertyValues().addPropertyValue(pv); 22 } finally { 23 this.parseState.pop(); 24 } 25 26 } 27 }
(八) parseQualifierElements()
解析 qualifier 屬性的實現邏輯:
1 public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) { 2 //第一步: 獲取 type 屬性 3 String typeName = ele.getAttribute("type"); 4 if(!StringUtils.hasLength(typeName)) { 5 this.error("Tag 'qualifier' must have a 'type' attribute", ele); 6 } else { 7 this.parseState.push(new QualifierEntry(typeName)); 8 9 try { 10 //第二步: 封裝的 AutowireCandidateQualifier 類 11 AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName); 12 qualifier.setSource(this.extractSource(ele)); 13 String value = ele.getAttribute("value"); 14 if(StringUtils.hasLength(value)) { 15 qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value); 16 } 17 18 NodeList nl = ele.getChildNodes(); 19 //第三步: 遍歷全部的子元素 20 for(int i = 0; i < nl.getLength(); ++i) { 21 Node node = nl.item(i); 22 //第四步: 判斷子元素的類型 23 if(this.isCandidateElement(node) && this.nodeNameEquals(node, "attribute")) { 24 Element attributeEle = (Element)node; 25 String attributeName = attributeEle.getAttribute("key"); 26 String attributeValue = attributeEle.getAttribute("value"); 27 if(!StringUtils.hasLength(attributeName) || !StringUtils.hasLength(attributeValue)) { 28 this.error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle); 29 return; 30 } 31 //第五步: 封裝的 BeanMetadataAttribute 類性 32 BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue); 33 attribute.setSource(this.extractSource(attributeEle)); 34 //第六步: qualifier 添加屬性 35 qualifier.addMetadataAttribute(attribute); 36 } 37 } 38 39 bd.addQualifier(qualifier); 40 } finally { 41 this.parseState.pop(); 42 } 43 } 44 }
到此, 咱們大體涵蓋了 processBeanDefinition() 方法當中的第一步 delegate.parseBeanDefinitionElement() 方法的實現邏輯。 絕望, 這麼長的代碼總結起來就一句代碼而已!! ค(TㅅT)
在 processBeanDefinition() 方法中, 第二步實現 自定義元素的解析 decorateBeanDefinitionIfRequired() 的邏輯:
1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { 2 return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null); 3 }
1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) { 2 BeanDefinitionHolder finalDefinition = definitionHolder; 3 NamedNodeMap attributes = ele.getAttributes(); 4 //第一步: 遍歷全部的 子元素 5 for(int i = 0; i < attributes.getLength(); ++i) { 6 Node node = attributes.item(i); 7 finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd); 8 } 9 10 NodeList children = ele.getChildNodes(); 11 //第二步: 遍歷全部的 子節點 12 for(int i = 0; i < children.getLength(); ++i) { 13 Node node = children.item(i); 14 if(node.getNodeType() == 1) { 15 finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd); 16 } 17 } 18 19 return finalDefinition; 20 }
1 public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) { 2 String namespaceUri = this.getNamespaceURI(node); 3 //第一步: 對非默認命名空間標籤的處理 4 if(!this.isDefaultNamespace(namespaceUri)) { 5 //第二步: 根據命名空間找到對應的處理器調用方法 6 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 7 if(handler != null) { 8 //第三步: 進行修飾 9 return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); 10 } 11 12 if(namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) { 13 this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); 14 } else if(this.logger.isDebugEnabled()) { 15 this.logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); 16 } 17 } 18 19 return originalDef; 20 }
1 public String getNamespaceURI(Node node) { return node.getNamespaceURI(); }
1 public boolean isDefaultNamespace(String namespaceUri) { 2 return !StringUtils.hasLength(namespaceUri) || "http://www.springframework.org/schema/beans".equals(namespaceUri); 3 }
在 processBeanDefinition() 方法中, 第三步註冊 BeanDefinition 的 registerBeanDefinition() 方法的實現邏輯
1 public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { 2 3 String beanName = definitionHolder.getBeanName(); 4 //第一步: 使用 beanName 作標誌 5 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 6 7 String[] aliases = definitionHolder.getAliases(); 8 if(aliases != null) { 9 String[] var4 = aliases; 10 int var5 = aliases.length; 11 12 for(int var6 = 0; var6 < var5; ++var6) { 13 String aliase = var4[var6]; 14 //第二步: 註冊全部別名 15 registry.registerAlias(beanName, aliase); 16 } 17 } 18 19 }
在 registerBeanDefinition() 方法中, 第一步使用 beanName 做爲 BeanDefinition 的標誌註冊, 實現的邏輯:
1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { 2 3 if(beanDefinition instanceof AbstractBeanDefinition) { 4 try { 5 //第一步: 對 AbstractBeanDefinition 的 methodOverrides 的校驗 6 ((AbstractBeanDefinition)beanDefinition).validate(); 7 } catch (BeanDefinitionValidationException var7) { 8 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var7); 9 } 10 } 11 12 Map var3 = this.beanDefinitionMap; 13 //第二步: 對全局變量進行同步 14 synchronized(this.beanDefinitionMap) { 15 //第三步: 緩存中獲取 BeanDefinition 16 BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); 17 if(oldBeanDefinition != null) { 18 if(!this.allowBeanDefinitionOverriding) { 19 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); 20 } 21 22 if(oldBeanDefinition.getRole() < beanDefinition.getRole()) { 23 if(this.logger.isWarnEnabled()) { 24 this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + " with a framework-generated bean definition ': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); 25 } 26 } else if(this.logger.isInfoEnabled()) { 27 this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); 28 } 29 } else { 30 //第四步: 記錄 beanName 31 this.beanDefinitionNames.add(beanName); 32 this.frozenBeanDefinitionNames = null; 33 } 34 //第五步: 註冊 beanDefinition, 放入到 Map 集合中 35 this.beanDefinitionMap.put(beanName, beanDefinition); 36 } 37 38 this.resetBeanDefinition(beanName); 39 }
原本想把 logger 還有 exception 信息都去掉, 可是看了一下, 裏面的內容說明了許多問題, 對梳理邏輯頗有幫助, 看這段代碼的時候應該過一遍。
在 registerBeanDefinition() 方法中, 第二步使用 別名註冊 BeanDefinition 的 registerAlias() 方法的實現邏輯:
1 public void registerAlias(String name, String alias) { 2 //第一步: beanName 和 alias 相同, 則刪除對應的 alias 3 if(alias.equals(name)) { 4 this.aliasMap.remove(alias); 5 } else { 6 if(!this.allowAliasOverriding()) { 7 String registeredName = (String)this.aliasMap.get(alias); 8 if(registeredName != null && !registeredName.equals(name)) { 9 throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); 10 } 11 } 12 13 this.checkForAliasCircle(name, alias); 14 //第二步: 註冊 Alias 15 this.aliasMap.put(alias, name); 16 } 17 18 }
在 processBeanDefinition() 方法中, 第四步通知完成註冊的方法 fireComponentRegistered() 方法, 留給子類擴展。
二 : alias 標籤
是否是以爲有點奔潰, 到如今爲止只是解決了一個 <bean> 標籤的處理。 可是, 可是來了,接下來剩下的標籤的處理相對於 <bean> 標籤的處理要簡單得多得多得多。
在 parseDefaultElement() 方法中, 第二步 processAliasRegistration() 方法的實現邏輯:
1 protected void processAliasRegistration(Element ele) { 2 //第一步: 獲取 beanName 和 alias 屬性 3 String name = ele.getAttribute("name"); 4 String alias = ele.getAttribute("alias"); 5 boolean valid = true; 6 if(!StringUtils.hasText(name)) { 7 this.getReaderContext().error("Name must not be empty", ele); 8 valid = false; 9 } 10 11 if(!StringUtils.hasText(alias)) { 12 this.getReaderContext().error("Alias must not be empty", ele); 13 valid = false; 14 } 15 16 if(valid) { 17 try { 18 //第二步: 註冊 alias 19 this.getReaderContext().getRegistry().registerAlias(name, alias); 20 } catch (Exception var6) { 21 this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6); 22 } 23 //第三步: 註冊完成後的通知事件 24 this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele)); 25 } 26 27 }
三 : import 標籤
在 parseDefaultElement() 方法中, 在第一步解析 import 標籤的 importBeanDefinitionResource() 的方法的實現:
1 protected void importBeanDefinitionResource(Element ele) { 2 //第一步: 獲取 resource 屬性 3 String location = ele.getAttribute("resource"); 4 if(!StringUtils.hasText(location)) { 5 this.getReaderContext().error("Resource location must not be empty", ele); 6 } else { 7 //第二步: 處理 placeHolder 的狀況 8 location = this.environment.resolveRequiredPlaceholders(location); 9 Set<Resource> actualResources = new LinkedHashSet(4); 10 //第三步: 判斷是相對路徑仍是絕對路徑 11 boolean absoluteLocation = false; 12 13 try { 14 absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); 15 } catch (URISyntaxException var11) { 16 ; 17 } 18 19 int importCount; 20 if(absoluteLocation) { 21 try { 22 //第四步: 是絕對路徑,直接加載 配置文件 23 importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources); 24 } catch (BeanDefinitionStoreException var10) { 25 this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10); 26 } 27 } else { 28 try { 29 //第五步: 相對路徑計算出絕對路徑, 加載配置文件 30 Resource relativeResource = this.getReaderContext().getResource().createRelative(location); 31 if(relativeResource.exists()) { 32 importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource); 33 actualResources.add(relativeResource); 34 } else { 35 String baseLocation = this.getReaderContext().getResource().getURL().toString(); 36 //第六步: 使用默認 ResourcePatternResolver 進行解析 37 importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources); 38 } 39 40 } 41 42 Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]); 43 //第七步: 通知監聽器 44 this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele)); 45 } 46 }
四 : beans 標籤
接觸過 Spring 的都熟悉 <beans> 標籤了, 在 一 中解析的 <bean> 標籤, 遞歸調用 bean 標籤的解析方法。 輕鬆略過. 哈哈哈哈哈 ( ^_^ )
解析自定義標籤 parseCustomElement()
解析自定義標籤的方法 parseCustomElement() 方法的實現邏輯:
1 public BeanDefinition parseCustomElement(Element ele) { 2 return this.parseCustomElement(ele, (BeanDefinition)null); 3 }
1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { 2 //第一步: 獲取對應的命名空間 3 String namespaceUri = this.getNamespaceURI(ele); 4 //第二步: 根據命名空間找到 NamespaceHandler 5 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 6 if(handler == null) { 7 this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); 8 return null; 9 } else { 10 //第三步: 調用自定義的 handler 的方法 11 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); 12 } 13 }
在 parseCustomElement() 方法中, 第二步 獲取 NamespaceHandler 方法中, readerContext 把 namespaceHandlerResolver 初始化爲 DefaultNamespaceHandlerResolver :
1 public NamespaceHandler resolve(String namespaceUri) { 2 //第一步: 獲取全部配置的 handler 3 Map<String, Object> handlerMappings = this.getHandlerMappings(); 4 //第二步: 獲取類名 5 Object handlerOrClassName = handlerMappings.get(namespaceUri); 6 if(handlerOrClassName == null) { 7 return null; 8 } else if(handlerOrClassName instanceof NamespaceHandler) { 9 //第三步: 已解析的狀況, 從緩存中獲取 10 return (NamespaceHandler)handlerOrClassName; 11 } else { 12 //第四步: 未解析, 經過類路徑, 反射建立類實例 13 String className = (String)handlerOrClassName; 14 15 try { 16 Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); 17 if(!NamespaceHandler.class.isAssignableFrom(handlerClass)) { 18 throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); 19 } else { 20 //第五步: 初始化類 21 NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass); 22 //第六步: 調用 NamespaceHandler 的初始化方法 23 namespaceHandler.init(); 24 //第七步: 記錄在緩存當中 25 handlerMappings.put(namespaceUri, namespaceHandler); 26 return namespaceHandler; 27 } 28 } 29 } 30 }
結合註釋, 仍是挺簡單的一段代碼來着的, 初始化一個 NamespaceHandler 類, 緩存也只是把類記錄在一個 Map 對象中。
在 resolve() 方法中, 第一步 getHandlerMappings() 方法獲取全部配置的 handler 的實現邏輯:
1 private Map<String, Object> getHandlerMappings() { 2 //第一步: 沒有緩存則進行緩存 (緩存就是 handlerMappings 屬性) 3 if(this.handlerMappings == null) { 4 synchronized(this) { 5 if(this.handlerMappings == null) { 6 try { 7 //第二步: 加載配置文件 8 Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); 9 if(this.logger.isDebugEnabled()) { 10 this.logger.debug("Loaded NamespaceHandler mappings: " + mappings); 11 } 12 13 Map<String, Object> handlerMappings = new ConcurrentHashMap(mappings.size()); 14 //第三步: 將配置文件 Properties 文件合併到 handlerMappings 中 15 CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); 16 this.handlerMappings = handlerMappings; 17 } 18 } 19 } 20 } 21 22 return this.handlerMappings; 23 }
關於加載的配置文件, 在 DefaultNamespaceHandlerResolver 類的構造函數中, 把 this.handlerMappingsLocation 初始化爲 META-INF/spring.handlers:
1 public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; 2 3 4 5 public DefaultNamespaceHandlerResolver(ClassLoader classLoader, String handlerMappingsLocation) { 6 this.logger = LogFactory.getLog(this.getClass()); 7 Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null"); 8 this.classLoader = classLoader != null?classLoader:ClassUtils.getDefaultClassLoader(); 9 //第一步: 初始化 10 this.handlerMappingsLocation = handlerMappingsLocation; 11 }
而後, 咱們瞄一眼 spring.handlers 配置文件:
1 http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler 2 http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler 3 http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
在 parseCustomElement() 方法中, 第三步調用 handler 的 parse() 方法的實現邏輯, 以 NamespaceHandlerSupport 類的實現爲例:
1 public BeanDefinition parse(Element element, ParserContext parserContext) { 2 return this.findParserForElement(element, parserContext).parse(element, parserContext); 3 }
1 private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { 2 //第一步: 獲取元素的名稱 3 String localName = parserContext.getDelegate().getLocalName(element); 4 //第二步: 根據名稱獲取對應的解析器 5 BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName); 6 if(parser == null) { 7 parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element); 8 } 9 10 return parser; 11 }
對於 parse() 方法, 在 AbstractBeanDefinitionParser 中找到了其實現方法:
1 public final BeanDefinition parse(Element element, ParserContext parserContext) { 2 //第一步: 調用自定義的解析函數 3 AbstractBeanDefinition definition = this.parseInternal(element, parserContext); 4 if(definition != null && !parserContext.isNested()) { 5 try { 6 //第二步: 獲取 id 屬性 7 String id = this.resolveId(element, definition, parserContext); 8 if(!StringUtils.hasText(id)) { 9 parserContext.getReaderContext().error("Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element); 10 } 11 12 String[] aliases = new String[0]; 13 //第三步: 獲取 name 屬性 14 String name = element.getAttribute("name"); 15 if(StringUtils.hasLength(name)) { 16 aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name)); 17 } 18 //第四步: AbstractBeanDefinition 轉換爲 BeanDefinitionHolder 對象 19 20 BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases); 21 this.registerBeanDefinition(holder, parserContext.getRegistry()); 22 if(this.shouldFireEvents()) { 23 //第五步: 通知監聽器 24 BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder); 25 this.postProcessComponentDefinition(componentDefinition); 26 parserContext.registerComponent(componentDefinition); 27 } 28 } catch (BeanDefinitionStoreException var9) { 29 parserContext.getReaderContext().error(var9.getMessage(), element); 30 return null; 31 } 32 } 33 34 return definition; 35 }
看起來不少, 其實只是 AbstractBeanDefinition 轉換爲 BeanDefinitionHolder 對象, 在 第一步的調用自定義解析函數的 parseInternal() 的實現邏輯, 在 AbstractSingleBeanDefinitionParser 類中找到了還方法的實現 ( AbstractBeanDefinitionParser 中定義該方法, 子類實現):
1 protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { 2 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); 3 String parentName = this.getParentName(element); 4 if(parentName != null) { 5 builder.getRawBeanDefinition().setParentName(parentName); 6 } 7 //第一步: 獲取 class 屬性 8 Class<?> beanClass = this.getBeanClass(element); 9 if(beanClass != null) { 10 builder.getRawBeanDefinition().setBeanClass(beanClass); 11 } else { 12 String beanClassName = this.getBeanClassName(element); 13 if(beanClassName != null) { 14 builder.getRawBeanDefinition().setBeanClassName(beanClassName); 15 } 16 } 17 18 builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); 19 if(parserContext.isNested()) { 20 //第二步: 設置 scope 屬性 21 builder.setScope(parserContext.getContainingBeanDefinition().getScope()); 22 } 23 //第三步: 設置 lazy-init 屬性 24 if(parserContext.isDefaultLazyInit()) { 25 builder.setLazyInit(true); 26 } 27 //第四步: 調用自定義的解析函數 28 this.doParse(element, parserContext, builder); 29 return builder.getBeanDefinition(); 30 }
在 parseInternal() 方法中, 第四步 doParse() 方法才真正調用了咱們本身寫的解析方法。
到此,咱們已經瞭解了 Spring 默認標籤 以及 自定義標籤的處理, 在接下來的內容當中, 將進入 Spring 在加載完 XML 配置文件後, 對 Bean 的初始化的工做。
ㄟ( ▔, ▔ )ㄏ 來個 Spring 的套路, FIREDAYWORKCOMPLETEDEVENT(new GOODNIGHT("(~﹃~)~zZ"));