【spring源码分析】IOC容器初始化(四)
前言:在【spring源码分析】IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程。
1 //DefaultBeanDefinitionDocumentReader 2 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { 3 // 进行bean标签解析 4 // 如果解析成功,则返回BeanDefinitionHolder,BeanDefinitionHolder为name和alias的BeanDefinition对象 5 // 如果解析失败,则返回null 6 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 7 if (bdHolder != null) { 8 // 进行标签处理,主要对bean标签的相关属性进行处理 如: p:name="测试用例" 9 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 10 try { 11 // 注册BeanDefinition 12 // Register the final decorated instance. 13 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 14 } catch (BeanDefinitionStoreException ex) { 15 getReaderContext().error("Failed to register bean definition with name '" + 16 bdHolder.getBeanName() + "'", ele, ex); 17 } 18 // 发出响应时间,通知监听器,已完成该bean标签的解析 19 // Send registration event. 20 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 21 } 22 }
前面分析了如何解析bean标签的默认属性,在进行BeanDefinition注册之前,还需对bean标签的相关属性进行处理,第9行代码处。
BeanDefinitionParserDelegate#decorateBeanDefinitionIfRequired
1 public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) { 2 return decorateBeanDefinitionIfRequired(ele, definitionHolder, null); 3 } 4 5 public BeanDefinitionHolder decorateBeanDefinitionIfRequired( 6 Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) { 7 8 // 解析完成后的返回值,封装了其自定义属性的BeandefinitionHolder 9 BeanDefinitionHolder finalDefinition = definitionHolder; 10 11 // #1.遍历属性,查看是否有适用于装饰的属性 12 // Decorate based on custom attributes first. 13 NamedNodeMap attributes = ele.getAttributes(); 14 for (int i = 0; i < attributes.getLength(); i++) { 15 Node node = attributes.item(i); 16 finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); 17 } 18 19 // #2.遍历子节点,查看是否有适用于装饰的子节点 20 // Decorate based on custom nested elements. 21 NodeList children = ele.getChildNodes(); 22 for (int i = 0; i < children.getLength(); i++) { 23 Node node = children.item(i); 24 if (node.getNodeType() == Node.ELEMENT_NODE) { 25 finalDefinition = decorateIfRequired(node, finalDefinition, containingBd); 26 } 27 } 28 return finalDefinition; 29 }
分析:
这里代码逻辑比较简单,就是遍历节点的属性或子节点,检查是否需要装饰的节点,如直接在bean标签里对属性赋值:p:name="XXX"。其核心点在第16行处与第25行处。
BeanDefinitionParserDelegate#decorateIfRequired
1 public BeanDefinitionHolder decorateIfRequired( 2 Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) { 3 4 // 首先获取自定义标签的命名空间 5 String namespaceUri = getNamespaceURI(node); 6 // 过滤掉默认的命名空间,因为这里是自定义空间的解析,默认命名空间上面已经进行了解析 7 if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) { 8 // 通过命名空间获取对应的空间处理器 9 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 10 if (handler != null) { 11 // 进行装饰处理 在SimplePropertyNamespaceHandler处理器中 12 BeanDefinitionHolder decorated = 13 handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd)); 14 if (decorated != null) { 15 return decorated; 16 } 17 } else if (namespaceUri.startsWith("http://www.springframework.org/")) { 18 error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node); 19 } else { 20 // A custom namespace, not to be handled by Spring - maybe "xml:...". 21 if (logger.isDebugEnabled()) { 22 logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]"); 23 } 24 } 25 } 26 return originalDef; 27 }
分析:
- 首先得到节点命名空间uri,并判断namespaceUri不为"http://www.springframework.org/schema/beans"。
- 然后通过namespaceUri解析出命名空间解析器,这里会调用DefaultNamespaceHandlerResolver#resolve函数,该函数在【spring源码分析】IOC容器初始化(三)中已经分析过。
- 最后通过SimplePropertyNamespaceHandler#decorate进行装饰处理。
SimplePropertyNamespaceHandler#decorate
1 public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { 2 // 如果当前节点是属性节点 3 if (node instanceof Attr) { 4 Attr attr = (Attr) node; 5 // 获取name、value属性 6 String propertyName = parserContext.getDelegate().getLocalName(attr); 7 String propertyValue = attr.getValue(); 8 // 获取bean的propertyValues集合 9 MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues(); 10 // 如果已经存在属性了,则报错 11 if (pvs.contains(propertyName)) { 12 parserContext.getReaderContext().error("Property '" + propertyName + "' is already defined using " + 13 "both <property> and inline syntax. Only one approach may be used per property.", attr); 14 } 15 // 如果属性name以-ref结尾,则需要进行解析,否则直接加入MutablePropertyValues集合中 16 if (propertyName.endsWith(REF_SUFFIX)) { 17 propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length()); 18 pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue)); 19 } 20 else { 21 pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue); 22 } 23 } 24 // 返回已经封装了property属性的BeanDefinitionHolder 25 return definition; 26 }
分析:
其实这段代码的逻辑也比较简单,就是获取解析节点的name、value属性,然后放入MutablePropertyValues集合中。
BeanDefinitionReaderUtils#registerBeanDefinition
1 public static void registerBeanDefinition( 2 BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) 3 throws BeanDefinitionStoreException { 4 5 // 注册beanName 6 // Register bean definition under primary name. 7 String beanName = definitionHolder.getBeanName(); 8 // 调用DefaultListableBeanFactory#registerBeanDefinition方法进行bean注册 9 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); 10 11 // 注册aliases 12 // Register aliases for bean name, if any. 13 String[] aliases = definitionHolder.getAliases(); 14 if (aliases != null) { 15 for (String alias : aliases) { 16 // 这里调用的是SimpleAliasRegistry#registerAlias 17 registry.registerAlias(beanName, alias); 18 } 19 } 20 }
分析:
BeanDefinition注册分两步:
- beanName注册(重点),这里会委托DefaultListableBeanFactory#registerBeanDefinition进行注册。
- aliases注册,同样这里会委托DefaultListableBeanFactory#registerAlias进行注册。
DefaultListableBeanFactory#registerBeanDefinition
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 7 // 校验BeanDefinition 8 // 这是注册前的最后一次校验,主要是对属性methodOverrides进行校验 9 if (beanDefinition instanceof AbstractBeanDefinition) { 10 try { 11 ((AbstractBeanDefinition) beanDefinition).validate(); 12 } catch (BeanDefinitionValidationException ex) { 13 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, 14 "Validation of bean definition failed", ex); 15 } 16 } 17 // 从缓存中获取指定beanName的BeanDefinition 18 BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); 19 // 如果缓存中存在 20 if (existingDefinition != null) { 21 // 如果存在但是不允许覆盖,则抛出异常 22 if (!isAllowBeanDefinitionOverriding()) { 23 throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); 24 } 25 // 覆盖BeanDefinition的ROLE大于被覆盖的ROLE,打印info日志 26 else if (existingDefinition.getRole() < beanDefinition.getRole()) { 27 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE 28 if (logger.isInfoEnabled()) { 29 logger.info("Overriding user-defined bean definition for bean '" + beanName + 30 "' with a framework-generated bean definition: replacing [" + 31 existingDefinition + "] with [" + beanDefinition + "]"); 32 } 33 } 34 // 如果覆盖BeanDefinition与被覆盖的BeanDefinition不相同,打印debug日志 35 else if (!beanDefinition.equals(existingDefinition)) { 36 if (logger.isDebugEnabled()) { 37 logger.debug("Overriding bean definition for bean '" + beanName + 38 "' with a different definition: replacing [" + existingDefinition + 39 "] with [" + beanDefinition + "]"); 40 } 41 } 42 // 其他,打印debug日志 43 else { 44 if (logger.isTraceEnabled()) { 45 logger.trace("Overriding bean definition for bean '" + beanName + 46 "' with an equivalent definition: replacing [" + existingDefinition + 47 "] with [" + beanDefinition + "]"); 48 } 49 } 50 // 允许覆盖,直接覆盖原来的BeanDefinition 51 this.beanDefinitionMap.put(beanName, beanDefinition); 52 } 53 // 如果缓存中不存在 54 else { 55 // 检测创建Bean阶段是否已经开启,如果开启,需要对beanDefinitionMap做并发控制 56 if (hasBeanCreationStarted()) { 57 // beanDefinitionMap为全局变量,避免并发情况 58 // Cannot modify startup-time collection elements anymore (for stable iteration) 59 synchronized (this.beanDefinitionMap) { 60 // 添加BeanDefinition到beanDefinitionMap中 61 this.beanDefinitionMap.put(beanName, beanDefinition); 62 // 更新beanName集合beanDefinitionNames 63 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); 64 updatedDefinitions.addAll(this.beanDefinitionNames); 65 updatedDefinitions.add(beanName); 66 this.beanDefinitionNames = updatedDefinitions; 67 // 从manualSingletonNames中移除beanName 68 if (this.manualSingletonNames.contains(beanName)) { 69 Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); 70 updatedSingletons.remove(beanName); 71 this.manualSingletonNames = updatedSingletons; 72 } 73 } 74 } 75 // 如果bean创建阶段未开启 76 else { 77 // Still in startup registration phase 78 // 添加BeanDefinition到beanDefinitionMap中 79 this.beanDefinitionMap.put(beanName, beanDefinition); 80 // 添加beanName到beanDefinitionNames集合中 81 this.beanDefinitionNames.add(beanName); 82 // 从manualSingletonNames中移除beanName 83 this.manualSingletonNames.remove(beanName); 84 } 85 this.frozenBeanDefinitionNames = null; 86 } 87 // 如果缓存存在,则更新beanName对应的缓存 88 if (existingDefinition != null || containsSingleton(beanName)) { 89 resetBeanDefinition(beanName); 90 } 91 }
分析:
整段函数理解起来还是比较顺畅的,这里谨记我们的最终落脚点beanDefinitionMap。
- 在BeanDefinition注册前会对其进行最后一次校验,判断方法覆盖是否与工厂方法并存,如果并存,则会抛出异常。
- 从缓存中查找是否存在BeanDefinition,如果存在并且不允许覆盖,则抛出异常,否则这几覆盖原来的BeanDefinition。
- 如果缓存中不存在BeanDefinition,则进行注册。
至此,BeanDefinition基于beanName和alias的维度,都已经注入到缓存中,接下来就是初始化然后使用bean了,接下来会继续进行分析,这里先看加载BeanDefinition的整个过程:
注:图片来源芋道源码
总结
过多的总结显得苍白无力,最后一张图片足以说明问题。
by Shawn Chen,2018.12.10日,晚。