spring 源码解析之 14注册解析的BeanDefinition DefaultBeanDefinitionDocumentReader.processBeanDefinition()
完成 Bean 标签解析的核心工作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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().fireComponentRegistered( new BeanComponentDefinition (bdHolder)); } }
解析工作分为三步:
解析默认标签;
解析默认标签中的自定义属性标签;
注册解析后的 BeanDefinition。
经过前面两个步骤的解析,这时的 BeanDefinition 已经可以满足后续的使用要求了,那么接下来的工作就是将这些 BeanDefinition 进行注册,也就是完成第三步。
注册 BeanDefinition 由 BeanDefinitionReaderUtils.registerBeanDefinition()
完成。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 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()) { 。。。。省略抛出异常 } else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { 。。。。省略日志 } else if (!beanDefinition.equals(oldBeanDefinition)) { 。。。。省略日志 } else { if (this .logger.isDebugEnabled()) { 。。。。 省略日志 } } 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 属性进行校验。其中有一点我在这里在说明一下methodOverrides不能和工厂方法并存,是因为实现methodOverrides需要使用动态代理来改变这个类,如果使用cglib,则需要修改字节码,如果使用了工厂方法,是直接返回bean,而动态代理是无法修改这个对象的
根据 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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()) { 。。。省略异常 } } checkForAliasCircle(name, alias); this .aliasMap.put(alias, name); } } }
注册 alias 和注册 BeanDefinition 的过程差不多。在最后调用了 checkForAliasCircle()
来对别名进行了检测。
1 2 3 4 5 6 7 8 9 10 11 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),加入集合中存在(3,A),(A,1)的情况则会出错。
到此为止BeanDefinition已经注册完成,下一步就是初始化bean。