當咱們建立了bean信息的承載實例以後, 即可以進行bean信息的各類屬性的解析了, 首先咱們進入parseBeanDefinitionAttributes方法,parseBeanDefinitionAttributes方法是對element全部元素屬性進行解析:
/**
* Apply the attributes of the given bean element to the given bean * definition. * @param ele bean declaration element * @param beanName bean name * @param containingBean containing bean definition * @return a bean definition initialized according to the bean element attributes */ public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, @Nullable BeanDefinition containingBean, AbstractBeanDefinition bd) { if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) { error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele); } 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()); } if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) { bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE))); } String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE); if (DEFAULT_VALUE.equals(lazyInit)) { lazyInit = this.defaults.getLazyInit(); } bd.setLazyInit(TRUE_VALUE.equals(lazyInit)); String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE); bd.setAutowireMode(getAutowireMode(autowire)); if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) { String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE); bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS)); } 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)); } if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) { bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE))); } 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); } 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); } if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) { bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE)); } if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) { bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE)); } return bd; }
經過以上代碼咱們能夠發現, 在1.0版本會有一個singleton 不過呢, 這個很快就被取代掉了, 使用的話會提示錯誤信息, 在新的版本里, 咱們使用了scpoe=「singleton」 做爲一個新的使用方式, 咱們都知道在spring中,所建立的bean 都被認爲默認認爲是單例的,而且經過scope這個關鍵字,即scope="singleton"。另外scope還有prototype、request、session、global session做用域。scope="prototype"多例。 scope就是一個做用域,若是有不太理解的話,能夠參照一下:Spring scope做用域詳解。在這裏只是看了一下scope標籤的解析, 那麼確定還會有不少的屬性, 咱們用或者沒有用過, 可是就不作講解了, 咱們知道spring是如何去作的就行了。java
例如:node
<bean id="car" class="test.CarFactoryBean"> <meta key = "key" value = "values"> </bean>
一般咱們經過配置文件使用spring的時候, 咱們會用到meta這個標籤,這個標籤中門會配置上, key, 和value這兩個屬性,spring
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); } } }
經過代碼, 咱們能夠發現, spring經過解析獲得的Element樹對象去獲得子節點, 而後便利子節點, 而且取得meta元素的key值和value的知值,而後將其存儲在attributeAccessor中。由此推測, 其餘的子集標籤也會是經過這種方式去加載, 而且這也符合咱們的預期。安全
至此咱們便完成了對xml文檔到GenericBenaDefinition的轉換, 也就是說咱們將xml裏面全部的配置都保存到了一個java實例中去了。不過GenericBenaDefinition只不過是一個子類的實現, 而大部分屬性都是保存到了AbstractBeanDefinition中去了。
當打開AbstractBeanDefinition這個類咱們能夠發現, 幾乎全部同bean配置的屬性都已經在這個類中進行了定義:session
public static final String SCOPE_DEFAULT = "";app
/** * Constant that indicates no autowiring at all. * @see #setAutowireMode */ public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; /** * Constant that indicates autowiring bean properties by name. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; /** * Constant that indicates autowiring bean properties by type. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; /** * Constant that indicates autowiring a constructor. * @see #setAutowireMode */ public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; /** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
這裏就不進行一一列舉了。ide
對於配置文件的解析已經完成了,咱們獲得了整個配置的內容, 接下來呢Spring作的事就是對註冊了。也就是processBeanDeefinition函數中的registerBeanDefinition(bdHolder, getReaderContext(),getRegistry())代碼的解析了。函數
/** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed */ 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 alias : aliases) { registry.registerAlias(beanName, alias); } } }
從上面的代碼能夠看出, 解析的beanDefinition都被註冊到BeanDefinitionRegistry類型的實例registry, 而對於beanDefinition的註冊分紅了兩部分:經過beanName的註冊以及經過別名註冊。ui
對於beanDefinition的註冊, 或許不少人認爲的方式就是將beanDefinition直接放入map中就行了, 使用beanName做爲key。確實,Spring就是這麼作的, 只不過除此以外, 它還作了點別的事情。
@Overridethis
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 { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
經過上面的代碼能夠發現, Spring確實將beanName放到了一個名字叫作beanDefinitionMap這樣的一個map之中,這個map的類型是線程安全的ConcurrentHashMap, 而在這以前,只不過是作了一些驗證。而對於經過別名進行註冊的BeanDefinition, 代碼是這樣的:
@Override
public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
經過以上的代碼咱們能夠發現, 在得知是註冊alias的步驟中, 這裏也會有一個名字爲aliasMap的map用來存儲註冊的別名,我這裏有個疑惑, 就是怎麼才能經過別名與原有的beanName進行映射呢? 若是都註冊了, 那麼將以哪一個爲準呢? 留給之後再看,留給評論。