源碼分析基於spring 4.3.xjava
本文經過閱讀源碼,分析spring如何讀取xml配置中的bean元數據。
關於閱讀源碼的思路,可參考 -- 如何閱讀java源碼node
本文主要分析XmlBeanFactory,XmlBeanFactory是一個簡單的容器, 從XML文件中讀取配置元數據。spring
BeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring.xml"));
XmlBeanFactory已過期,但好在簡單,便於分析源碼。安全
XmlBeanFactory#構造函數 -> XmlBeanDefinitionReader#loadBeanDefinitions
-> XmlBeanDefinitionReader#doLoadBeanDefinitions微信
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); // #1 return registerBeanDefinitions(doc, resource); // #2 } ... }
#1
加載xml到Document類(使用org.w3c.dom讀取xml文件)#2
registerBeanDefinitions -> 解析xml數據dom
XmlBeanDefinitionReader#registerBeanDefinitionside
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // #1 int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); // #2 return getRegistry().getBeanDefinitionCount() - countBefore; }
#1
構建BeanDefinitionDocumentReader#2
createReaderContext -> 構建ReaderContext,ReaderContext中存放了xml的resource,XmlBeanDefinitionReader等信息,這些後面都要使用。
registerBeanDefinitions -> 使用BeanDefinitionDocumentReader解析xml數據函數
注意,ReaderContext中存放了XmlBeanDefinitionReader,而XmlBeanDefinitionReader中存放了bean註冊器BeanDefinitionRegistry(後面註冊BeanDefinition要使用)。這個註冊器就是XmlBeanFactory,XmlBeanFactory中構建XmlBeanDefinitionReader時將this做爲Registry參數
XmlBeanDefinitionReader#reader源碼分析
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
XmlBeanFactory的父類DefaultListableBeanFactory實現了BeanDefinitionRegistry。post
DefaultBeanDefinitionDocumentReader#registerBeanDefinitions -> DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = createDelegate(getReaderContext(), root, parent); if (this.delegate.isDefaultNamespace(root)) { // #1 String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); // #2 if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isInfoEnabled()) { logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return; } } } preProcessXml(root); // #3 parseBeanDefinitions(root, this.delegate); // #4 postProcessXml(root); this.delegate = parent; }
#1
判斷元素的命名空間是否爲spring的beans空間,這個方法後面也有使用#2
處理PROFILE元素屬性#3
預處理,爲子類提供的擴展方法#4
parseBeanDefinitions -> 解析beans元素
DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); // #1 } else { delegate.parseCustomElement(ele); // #2 } } } } else { delegate.parseCustomElement(root); } }
#1
對於beans命名空間的元素,使用默認的方法進行解析#2
處理非beans命名空間的元素,使用對應的解析器處理
用戶也能夠自定義標籤及標籤解析器。
DefaultBeanDefinitionDocumentReader#parseDefaultElement
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // #1 importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // #2 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // #3 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // #4 doRegisterBeanDefinitions(ele); } }
#1
解析import元素#2
解析alias元素#3
解析bean元素#4
解析beans元素
主要看對bean元素的解析,DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); // #1 if (bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); // #2 try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); // #3 } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); // #4 } }
#1
根據xmleizo,生成BeanDefinitionHolder#2
應用NamespaceHandler#decorate擴展方法#3
將BeanDefinition註冊到spring上下文#4
發送註冊事件
這裏出現了一個很重要的類BeanDefinition。
BeanDefinition是spring對bean元數據的抽象, 是配置文件中<bean>
元素在spring容器中的內部表示類,存儲了bean的元數據, 如屬性PropertyValues, BeanClassName,Scope等。
BeanDefinitionHolder中持有BeanDefinition實例,以及beanName和aliases屬性。
BeanDefinitionParserDelegat#parseBeanDefinitionElement有幾個重載方法,最終都調用以下方法
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } AbstractBeanDefinition bd = createBeanDefinition(className, parent); // #1 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); // #2 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); // #3 parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); // #4 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // #5 parseConstructorArgElements(ele, bd); // #6 parsePropertyElements(ele, bd); // #7 parseQualifierElements(ele, bd); // #8 bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } ... }
#1
使用className和parent建立BeanDefinition#2
處理scope等元素屬性#3
處理meta元素屬性#4
處理lookup-method元素屬性#5
處理replaced-method元素屬性#6
處理constructor-arg構造方法參數#7
處理property元素#8
處理qualifier元素
看一下如何處理property元素
BeanDefinitionParserDelegate#parsePropertyElements -> BeanDefinitionParserDelegate#parsePropertyElement
public void parsePropertyElement(Element ele, BeanDefinition bd) { String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // #1 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); // #2 PropertyValue pv = new PropertyValue(propertyName, val); // #3 parseMetaElements(ele, pv); pv.setSource(extractSource(ele)); bd.getPropertyValues().addPropertyValue(pv); // #4 } finally { this.parseState.pop(); } }
#1
解析屬性名#2
將xml配置的屬性值轉化爲內部表示類#3
建立PropertyValue,PropertyValue中name存放屬性名,value存放了xml配置原始值。#4
添加到BeanDefinition,BeanDefinition使用MutablePropertyValues存放全部的屬性信息。
xml配置原始值並非屬性最終值,而是xml配置在spring中對應的內部表示類,如property元素的value屬性會表示爲TypedStringValue(相似於BeanDefinition表示<bean>元素)。
BeanDefinitionParserDelegate#parsePropertyValue
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) { ... boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE); 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) { // #1 String refName = ele.getAttribute(REF_ATTRIBUTE); if (!StringUtils.hasText(refName)) { error(elementName + " contains empty 'ref' attribute", ele); } RuntimeBeanReference ref = new RuntimeBeanReference(refName); ref.setSource(extractSource(ele)); return ref; } else if (hasValueAttribute) { // #2 TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE)); valueHolder.setSource(extractSource(ele)); return valueHolder; } else if (subElement != null) { // #3 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
若是property元素存在ref屬性,解析爲RuntimeBeanReference#2
若是存在value屬性,解析爲TypedStringValue#3
若是存在子標籤,就解析子標籤。子標籤和spring內部表示類對應以下
子標籤爲bean,解析爲BeanDefinitionHolder
子標籤爲ref,解析爲RuntimeBeanReference
子標籤爲idref,解析爲RuntimeBeanNameReference
子標籤爲value,解析爲TypedStringValue
子標籤爲null,解析爲TypedStringValue
子標籤爲array,解析爲ManagedArray
子標籤爲list,解析爲ManagedList
子標籤爲set,解析爲ManagedSet
子標籤爲map,解析爲ManagedMap
子標籤爲props,解析爲ManagedProperties
回到DefaultBeanDefinitionDocumentReader#processBeanDefinition方法#3
步驟, 看一下如何將BeanDefinition註冊到spring上下文
BeanDefinitionReaderUtils#registerBeanDefinition
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // #1 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); // #2 } } }
#1
使用beanName註冊bean#2
註冊別名alias
註冊器registry從ReaderContext中獲取,實際就是DefaultListableBeanFactory(注意上文對ReaderContext的說明)。
DefaultListableBeanFactory#registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ... BeanDefinition oldBeanDefinition; oldBeanDefinition = this.beanDefinitionMap.get(beanName); if (oldBeanDefinition != null) { ... } else { if (hasBeanCreationStarted()) { // #1 synchronized (this.beanDefinitionMap) { // #2 this.beanDefinitionMap.put(beanName, beanDefinition); // #3 List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // #4 if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; // #5 } } } else { // #6 this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
#1
判斷spring是否進入構建bean的階段#2
beanDefinitionNames/manualSingletonNames不是線程安全類,須要加鎖同步#3
添加beanDefinition到DefaultListableBeanFactory#beanDefinitionMap#4
經過寫時複製,添加beanName到DefaultListableBeanFactory#beanDefinitionNames#5
經過寫時複製,刪除manualSingletonNames的DefaultListableBeanFactory#beanDefinitionNames#6
還在註冊階段,不須要加鎖同步
最後, 看一下DefaultBeanDefinitionDocumentReader#parseBeanDefinitions方法#2
步驟對非beans空間的xml標籤的處理, BeanDefinitionParserDelegate#parseCustomElement
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); // #1 if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); // #2 }
#1
經過命名空間獲取特定的NamespaceHandler#2
使用NamespaceHandler進行處理
若是您以爲本文不錯,歡迎關注個人微信公衆號,您的關注是我堅持的動力!