【死磕 Spring】----- IOC 之注册解析的 BeanDefinition

DefaultBeanDefinitionDocumentReader.processBeanDefinition() 完成 Bean 标签解析的核心工作,如下:

 
 
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {

  2. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

  3. if (bdHolder != null) {

  4. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

  5. try {

  6. // Register the final decorated instance.

  7. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

  8. }

  9. catch (BeanDefinitionStoreException ex) {

  10. getReaderContext().error("Failed to register bean definition with name '" +

  11. bdHolder.getBeanName() + "'", ele, ex);

  12. }

  13. // Send registration event.

  14. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

  15. }

  16. }

解析工作分为三步:1、解析默认标签;2、解析默认标签后下得自定义标签;3、注册解析后的 BeanDefinition。经过前面两个步骤的解析,这时的 BeanDefinition 已经可以满足后续的使用要求了,那么接下来的工作就是将这些 BeanDefinition 进行注册,也就是完成第三步。

注册 BeanDefinition 由 BeanDefinitionReaderUtils.registerBeanDefinition() 完成。如下:

 
 
  1. public static void registerBeanDefinition(

  2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

  3. throws BeanDefinitionStoreException {

  4. // 注册 beanName

  5. String beanName = definitionHolder.getBeanName();

  6. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

  7. // 注册 alias

  8. String[] aliases = definitionHolder.getAliases();

  9. if (aliases != null) {

  10. for (String alias : aliases) {

  11. registry.registerAlias(beanName, alias);

  12. }

  13. }

  14. }

首先通过 beanName 注册 BeanDefinition ,然后再注册别名 alias。BeanDefinition 的注册由接口 BeanDefinitionRegistry 定义。

通过 beanName 注册

BeanDefinitionRegistry.registerBeanDefinition() 实现通过 beanName 注册 BeanDefinition,如下:

 
 
  1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

  2. throws BeanDefinitionStoreException {

  3. // 校验 beanName 与 beanDefinition

  4. Assert.hasText(beanName, "Bean name must not be empty");

  5. Assert.notNull(beanDefinition, "BeanDefinition must not be null");

  6. if (beanDefinition instanceof AbstractBeanDefinition) {

  7. try {

  8. // 校验 BeanDefinition

  9. // 这是注册前的最后一次校验了,主要是对属性 methodOverrides 进行校验

  10. ((AbstractBeanDefinition) beanDefinition).validate();

  11. }

  12. catch (BeanDefinitionValidationException ex) {

  13. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

  14. "Validation of bean definition failed", ex);

  15. }

  16. }

  17. BeanDefinition oldBeanDefinition;

  18. // 从缓存中获取指定 beanName 的 BeanDefinition

  19. oldBeanDefinition = this.beanDefinitionMap.get(beanName);

  20. /**

  21. * 如果存在

  22. */

  23. if (oldBeanDefinition != null) {

  24. // 如果存在但是不允许覆盖,抛出异常

  25. if (!isAllowBeanDefinitionOverriding()) {

  26. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

  27. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +

  28. "': There is already [" + oldBeanDefinition + "] bound.");

  29. }

  30. //

  31. else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {

  32. // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE

  33. if (this.logger.isWarnEnabled()) {

  34. this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +

  35. "' with a framework-generated bean definition: replacing [" +

  36. oldBeanDefinition + "] with [" + beanDefinition + "]");

  37. }

  38. }

  39. // 覆盖 beanDefinition 与 被覆盖的 beanDefinition 不是同类

  40. else if (!beanDefinition.equals(oldBeanDefinition)) {

  41. if (this.logger.isInfoEnabled()) {

  42. this.logger.info("Overriding bean definition for bean '" + beanName +

  43. "' with a different definition: replacing [" + oldBeanDefinition +

  44. "] with [" + beanDefinition + "]");

  45. }

  46. }

  47. else {

  48. if (this.logger.isDebugEnabled()) {

  49. this.logger.debug("Overriding bean definition for bean '" + beanName +

  50. "' with an equivalent definition: replacing [" + oldBeanDefinition +

  51. "] with [" + beanDefinition + "]");

  52. }

  53. }

  54. // 允许覆盖,直接覆盖原有的 BeanDefinition

  55. this.beanDefinitionMap.put(beanName, beanDefinition);

  56. }

  57. /**

  58. * 不存在

  59. */

  60. else {

  61. // 检测创建 Bean 阶段是否已经开启,如果开启了则需要对 beanDefinitionMap 进行并发控制

  62. if (hasBeanCreationStarted()) {

  63. // beanDefinitionMap 为全局变量,避免并发情况

  64. synchronized (this.beanDefinitionMap) {

  65. //

  66. this.beanDefinitionMap.put(beanName, beanDefinition);

  67. List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);

  68. updatedDefinitions.addAll(this.beanDefinitionNames);

  69. updatedDefinitions.add(beanName);

  70. this.beanDefinitionNames = updatedDefinitions;

  71. if (this.manualSingletonNames.contains(beanName)) {

  72. Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);

  73. updatedSingletons.remove(beanName);

  74. this.manualSingletonNames = updatedSingletons;

  75. }

  76. }

  77. }

  78. else {

  79. // 不会存在并发情况,直接设置

  80. this.beanDefinitionMap.put(beanName, beanDefinition);

  81. this.beanDefinitionNames.add(beanName);

  82. this.manualSingletonNames.remove(beanName);

  83. }

  84. this.frozenBeanDefinitionNames = null;

  85. }

  86. if (oldBeanDefinition != null || containsSingleton(beanName)) {

  87. // 重新设置 beanName 对应的缓存

  88. resetBeanDefinition(beanName);

  89. }

  90. }

处理过程如下:

  • 首先 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 的注册。

 
 
  1. public void registerAlias(String name, String alias) {

  2. // 校验 name 、 alias

  3. Assert.hasText(name, "'name' must not be empty");

  4. Assert.hasText(alias, "'alias' must not be empty");

  5. synchronized (this.aliasMap) {

  6. // name == alias 则去掉alias

  7. if (alias.equals(name)) {

  8. this.aliasMap.remove(alias);

  9. }

  10. else {

  11. // 缓存缓存记录

  12. String registeredName = this.aliasMap.get(alias);

  13. if (registeredName != null) {

  14. // 缓存中的相等,则直接返回

  15. if (registeredName.equals(name)) {

  16. // An existing alias - no need to re-register

  17. return;

  18. }

  19. // 不允许则抛出异常

  20. if (!allowAliasOverriding()) {

  21. throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +

  22. name + "': It is already registered for name '" + registeredName + "'.");

  23. }

  24. }

  25. // 当 A --> B 存在时,如果再次出现 A --> B --> C 则抛出异常

  26. checkForAliasCircle(name, alias);

  27. // 注册 alias

  28. this.aliasMap.put(alias, name);

  29. }

  30. }

  31. }

注册 alias 和注册 BeanDefinition 的过程差不多。在最好调用了 checkForAliasCircle() 来对别名进行了检测。

 
 
  1. public boolean hasAlias(String name, String alias) {

  2. for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {

  3. String registeredName = entry.getValue();

  4. if (registeredName.equals(name)) {

  5. String registeredAlias = entry.getKey();

  6. return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias));

  7. }

  8. }

  9. return false;

  10. }

如果 name 、 alias 为 1 、3 ,则构成 (1,3),加入集合中存在(A,1)、(3,A)的情况则会出错。

到这里 BeanDefinition、alias 都已经注入到缓存中,下一步则是等待初始化使用了。


原文发布时间为:2018-09-28

本文作者:Java技术驿站

本文来自云栖社区合作伙伴“Java技术驿站”,了解相关信息可以关注“Java技术驿站”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值