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日,晚。

  • 相关阅读:
    前端微服务
    日志系统的设计
    js解决数据精度问题
    前端取不到header 里面的内容问题
    sql server 数据库查询 json 数据乱码
    IDEA 根据 DCEVM + Hotswap Agent 实现项目热部署
    Redis 常用命令
    Spring Data JPA native query 分页
    十八年开发经验分享(06)递归程序构造
    十八年开发经验分享(07)递归程序设计
  • 原文地址:https://www.cnblogs.com/developer_chan/p/10087786.html
Copyright © 2011-2022 走看看