zoukankan      html  css  js  c++  java
  • 【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日,晚。

  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/developer_chan/p/10087786.html
Copyright © 2011-2022 走看看