本文作者:chenssy
出处:http://cmsblogs.com/?p=2763
在学习Spring源码
的过程中发现的好站+好贴,感谢作者。Spring版本:Spring 5.0.6.RELEASE
DefaultBeanDefinitionDocumentReader.processBeanDefinition()
完成 Bean
标签解析的核心工作,如下:
protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered( new BeanComponentDefinition (bdHolder)); } }
解析工作分为三步:
解析默认标签;
解析默认标签后下得自定义标签;
注册解析后的 BeanDefinition
。
经过前面两个步骤的解析,这时的 BeanDefinition
已经可以满足后续的使用要求了,那么接下来的工作就是将这些 BeanDefinition
进行注册,也就是完成第三步。 注册 BeanDefinition
由 BeanDefinitionReaderUtils.registerBeanDefinition()
完成。
如下:
public static void registerBeanDefinition ( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
首先通过 beanName
注册 BeanDefinition
,
然后再注册别名 alias
。
BeanDefinition
的注册由接口 BeanDefinitionRegistry
定义。
通过 beanName 注册 BeanDefinitionRegistry.registerBeanDefinition()
实现通过 beanName
注册 BeanDefinition
,如下:
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 oldBeanDefinition; oldBeanDefinition = this .beanDefinitionMap.get(beanName); if (oldBeanDefinition != null ) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException ( beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound." ); } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { if (this .logger.isWarnEnabled()) { this .logger.warn( "Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]" ); } } else if (!beanDefinition.equals(oldBeanDefinition)) { if (this .logger.isInfoEnabled()) { this .logger.info( "Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]" ); } } else { if (this .logger.isDebugEnabled()) { this .logger.debug( "Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]" ); } } this .beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { 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 { this .beanDefinitionMap.put(beanName, beanDefinition); this .beanDefinitionNames.add(beanName); this .manualSingletonNames.remove(beanName); } this .frozenBeanDefinitionNames = null ; } if (oldBeanDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }
处理过程如下:
首先 BeanDefinition
进行校验,该校验也是注册过程中的最后一次校验了,主要是对 AbstractBeanDefinition
的 methodOverrides
属性进行校验
根据 beanName
从缓存中获取 BeanDefinition
,如果缓存中存在,则根据 allowBeanDefinitionOverriding 标志来判断是否允许覆盖,如果允许则直接覆盖,否则抛出 BeanDefinitionStoreException 异常
若缓存中没有指定 beanName
的 BeanDefinition
,则判断当前阶段是否已经开始了 Bean
的创建阶段<>,如果是,则需要对 beanDefinitionMap
进行加锁控制并发问题,否则直接设置即可。对于 hasBeanCreationStarted()
方法后续做详细介绍,这里不过多阐述。
若缓存中存在该 beanName
或者 单利 bean
集合中存在该 beanName
,则调用 resetBeanDefinition()
重置 BeanDefinition
缓存。
其实整段代码的核心就在于 this.beanDefinitionMap.put(beanName, beanDefinition);
。
BeanDefinition
的缓存也不是神奇的东西,就是定义 map
,key
为 beanName
,value
为 BeanDefinition
。
注册 alias BeanDefinitionRegistry.registerAlias
完成 alias
的注册。
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); } else { String registeredName = this .aliasMap.get(alias); if (registeredName != null ) { if (registeredName.equals(name)) { return ; } if (!allowAliasOverriding()) { throw new IllegalStateException ( "Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'." ); } } checkForAliasCircle(name, alias); this .aliasMap.put(alias, name); } } }
注册 alias
和注册 BeanDefinition
的过程差不多。在最后调用了 checkForAliasCircle()
来对别名进行了检测。
public boolean hasAlias (String name, String alias) { for (Map.Entry<String, String> entry : this .aliasMap.entrySet()) { String registeredName = entry.getValue(); if (registeredName.equals(name)) { String registeredAlias = entry.getKey(); return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)); } } return false ; }
如果 name
、 alias
为 1 、3 ,则构成 (1,3) ,加入集合中存在(A,1) 、(3,A) 的情况则会出错。 到这里 BeanDefinition
、alias
都已经注入到缓存中,下一步则是等待初始化使用了。