上文咱們主要學習了Spring是如何獲取xml配置文件而且將其轉換成Document,咱們知道xml文件是由各類標籤組成,Spring須要將其解析成對應的配置信息。以前提到過Spring中的標籤包括默認標籤和自定義標籤兩種,而兩種標籤的用法以及解析方式存在着很大的不一樣,本文詳細分析默認標籤的解析過程。html
默認標籤的解析是在parseDefaultElement函數中進行的,函數中的功能邏輯一目瞭然,分別對4種不一樣標籤(import、alias、bean和 beans)作了不一樣的處理。node
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 對import標籤的處理 importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 對alias標籤的處理 processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 對bean標籤的處理 processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse // 對beans標籤的處理 doRegisterBeanDefinitions(ele); } }
在4種標籤的解析中,對bean標籤的解析最爲複雜也最爲重要,這是本文重點分析對象,若是能理解此標籤的解析過程,其餘標籤的解析天然會迎刃而解。首先咱們進入函數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)); } }
大體的邏輯總結以下: 緩存
下面會針對各個操做作進一步分析。併發
首先咱們從元素解析及信息提取開始,也就是BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele),進入BeanDefinitionDelegate類的parseBeanDefinitionElement方法:ide
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) { return parseBeanDefinitionElement(ele, null); } public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { // 解析id屬性 String id = ele.getAttribute(ID_ATTRIBUTE); // 解析name屬性 String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); // 分割name屬性 List<String> aliases = new ArrayList<String>(); 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"); } } if (containingBean == null) { checkNameUniqueness(beanName, aliases, ele); } AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try { // 若是不存在beanName那麼根據Spring中提供的命名規則爲當前bean生成對應的beanName if (containingBean != null) { beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { beanName = this.readerContext.generateBeanName(beanDefinition); // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. 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); return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } return null; }
以上即是對默認標籤解析的全過程了。在開始對屬性展開全面解析前,Spring又作了一些功能劃分,主要以下:函數
咱們進一步地查看步驟2中對標籤其餘屬性的解析過程:學習
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; // 解析class屬性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; // 解析parent屬性 if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } // 建立用於承載屬性的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()); // 解析replaced-method屬性 parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); // 解析構造函數參數 parseConstructorArgElements(ele, bd); // 解析property子元素 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標籤的全部屬性解析,不論經常使用的仍是不經常使用的咱們都看到了,儘管有些複雜的屬性還須要進一步的解析。咱們着重看一些複雜標籤屬性的解析。ui
BeanDefinition是一個接口,在Spring中有三個實現類:RootBeanDefinition、ChildBeanDefinition以及GenericBeanDefinition,均繼承自AbstractBeanDefiniton,其中BeanDefinition是配置文件<bean>元素標籤在容器中的內部表示形式。<bean>元素標籤擁有class、scope、lazy-init等配置屬性,BeanDefinition則提供了相應的beanClass、scope、lazyInit屬性,BeanDefinition和<bean>中的屬性是一一對應的。其中RootBeanDefinition是最經常使用的實現類,它對應通常性的<bean>元素標籤, GenericBeanDefinition是自2.5版本之後新加入的bean文件配置屬性定義類,是一站式服務類。this
在配置文件中能夠定義父<bean>和子<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefiniton表示,而沒有父<bean>的<bean>就使用RootBeanDefinition表示。
Spring經過BeanDefinition將配置文件中的<bean>配置信息轉換爲容器的內部表示,並將這些BeanDefiniton註冊到BeanDefinitonRegistry中。Spring容器的BeanDefinitionRegistry就像是Spring配置信息的內存數據庫,主要是以map的形式保存,後續操做直接從BeanDefinitionRegistry中讀取配置信息。
由此可知,要解析屬性首先要建立用於承載屬性的實例,也就是建立GenericBeanDefinition類型的實例。而代碼createBeanDefinition(className,parent)的做用就是實現此功能:
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); } public static AbstractBeanDefinition createBeanDefinition( String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); // parentName可能爲空 bd.setParentName(parentName); if (className != null) { // 若是classLoader不爲空,則使用已傳入的classLoader加載類對象,不然只是記錄className if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; }
當咱們建立了bean信息的承載實例後,即可以開始各類屬性解析了,這部分的主要邏輯在parseBeanDefinitionAttributes方法中:
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) { // 解析scope屬性 if (ele.hasAttribute(SCOPE_ATTRIBUTE)) { // Spring 2.x "scope" attribute bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE)); if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // scope與singleton兩個屬性只能指定其中之一,不能夠同時出現,不然Spring將會報出異常 error("Specify either 'scope' or 'singleton', not both", ele); } } // 解析singleton屬性 else if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { // Spring 1.x "singleton" attribute bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ? BeanDefinition.SCOPE_SINGLETON : BeanDefinition.SCOPE_PROTOTYPE); } else if (containingBean != null) { // Take default from containing bean in case of an inner bean definition. // 在嵌入beanDefinition狀況下且沒有單獨指定scope屬性則使用父類默認的屬性 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(); } // 若沒有設置或設置成其餘字符都會被設置爲false bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); // 解析autowire屬性 String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); // 解析dependency-check屬性 String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE); bd.setDependencyCheck(getDependencyCheck(dependencyCheck)); // 解析depends-on屬性 if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } // 解析autowire-candidate屬性 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); if (!"".equals(initMethodName)) { 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); if (!"".equals(destroyMethodName)) { 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; }
咱們能夠清楚地看到Spring完成了對全部bean屬性的解析,這些屬性中有不少是咱們常用的,也有些是咱們不熟悉的,有興趣能夠查閱相關資料進一步瞭解。固然除了這部分屬性解析,後面還有一些其餘的屬性解析(好比constructor-arg、property等),在此就不所有列出了。
至此便完成了對XML文檔到GenericBeanDefinition的轉換,也就是說到這裏,XML中全部的配置均可以在GenericBeanDefinition的實例類中找到對應的屬性。
GenericBeanDefinition只是子類實現,大部分的通用屬性都保存在了AbstractBeanDefinition中,因此這裏再次經過AbstractBeanDefinition的屬性來回顧一下都解析了哪些對應的配置,以加深理解:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { // 此處省略靜態變量以及final常量 /** bean的做用範圍,對應bean屬性scope */ private String scope = SCOPE_DEFAULT; /** 是不是單例,來自bean屬性scope */ private boolean singleton = true; /** 是不是原型,來自bean屬性scope */ private boolean prototype = false; /** 是不是抽象,對應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 */ private String[] dependsOn; /** autowire-candidate屬性設置爲false,這樣容器在查找自動裝配對象時, *將不考慮該bean,即它不會被考慮做爲其餘bean自動裝配的候選 *者,可是該bean自己仍是可使用自動裝配來注入其餘bean的 *對應bean屬性autowire-candidate */ private boolean autowireCandidate = true; /** 自動裝配時當出現多個bean候選着時,將做爲首選着,對應bean屬性primary */ private boolean primary = false; /** */ private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<String, AutowireCandidateQualifier>(0); /** */ private boolean nonPublicAccessAllowed = true; /** */ private boolean lenientConstructorResolution = true; /** */ private ConstructorArgumentValues constructorArgumentValues; /** */ private MutablePropertyValues propertyValues; /** */ private MethodOverrides methodOverrides = new MethodOverrides(); /** */ private String factoryBeanName; /** */ private String factoryMethodName; /** */ private String initMethodName; /** */ private String destroyMethodName; /** */ private boolean enforceInitMethod = true; /** */ private boolean enforceDestroyMethod = true; /** */ private boolean synthetic = false; /** */ private int role = BeanDefinition.ROLE_APPLICATION; /** */ private String description; /** 這個bean定義的資源 */ private Resource resource; }
解析完成以後獲得的beanDinition已經能夠知足後續的使用要求了,惟一還剩下的工做就是註冊,也就是processBeanDefinition函數中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext(). get())所完成的工做:
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String aliase : aliases) { registry.registerAlias(beanName, aliase); } } }
從上面的代碼能夠看出,解析好的beanDefinition都會被註冊到BeanDefinitionRegistry類型的實例registry中,beanDefinition的註冊分紅了兩部分:經過beanName的註冊以及經過別名的註冊。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { // 註冊前的最後一次校驗,這裏的校驗不一樣於以前的XML文件校驗 // 主要是對於AbstractBeanDefinition屬性中的methodOverrides校驗 // 校驗methodOverrides是否與工廠方法並存或者methodOverrides對應的方法根本不存在 ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; // 由於beanDefinitionMap是全局變量,這裏確定會存在併發訪問的狀況 synchronized (this.beanDefinitionMap) { oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 處理註冊已經註冊的beanName狀況 if (oldBeanDefinition != null) { // 若是對應的BeanName已經註冊而且在配置中配置了bean不容許被覆蓋,則拋出異常 if (!this.allowBeanDefinitionOverriding) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } else { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } } else { // 記錄beanName this.beanDefinitionNames.add(beanName); this.frozenBeanDefinitionNames = null; } // 註冊beanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); } // 重置全部beanName對應的緩存 if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
如上,在對於bean的註冊處理方式上,主要進行了以下幾個步驟:
public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); // 若是beanName與alias相同的話不記錄alias,並刪除對應的alias if (alias.equals(name)) { this.aliasMap.remove(alias); } else { // 若是alias不容許被覆蓋則拋出異常 if (!allowAliasOverriding()) { String registeredName = this.aliasMap.get(alias); if (registeredName != null && !registeredName.equals(name)) { throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } } // 當A->B存在時,若再次出現A->C->B時候則會拋出異常 checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); } }
由以上代碼中能夠得知註冊alias的步驟以下:
本文主要集中在分析從如何將默認xml標籤解析成BeanDefinition到將其註冊到容器中這一過程,至此Spring對配置的轉化工做就完成了,後面就要開始Bean的獲取這部分的邏輯的分析了。