Spring源码解析(四)Spring是怎么处理BeanDefinition的?

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 上一篇文章中分析了 BeanDefinition是怎么被解析出来的,在这一篇文章中我们主要看下 解析完了之后所做的事情;1一、DefaultBeanDefinitionDocumentReader源码入口DefaultBeanDefinitionDocumentReader #processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

作者石臻臻, CSDN博客之星Top5Kafka Contributornacos Contributor华为云 MVP ,腾讯云TVP, 滴滴Kafka技术专家KnowStreaming


KnowStreaming  是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!

上一篇文章中分析了 BeanDefinition是怎么被解析出来的,在这一篇文章中我们主要看下 解析完了之后所做的事情;

1一、DefaultBeanDefinitionDocumentReader


源码入口

DefaultBeanDefinitionDocumentReader #processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)

/**
  * Process the given bean element, parsing the bean definition
  * and registering it with the registry.
  */
 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
  //这个bdHoder就是被解析完成之后的BeanDefinition;上篇分析了,这里不再赘述
  BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
  if (bdHolder != null) {
   //这里是修饰一下BeanDefinition,这里以后再单独分析;TODO...
   bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
   try {
    /**注册BeanDefinition;
    *1.DefaultBeanDefinitionDocumentReader里面持有XmlReaderContext readerContext;
    *2.XmlReaderContext extends AbstractBeanDefinitionReader,这个类里面持有BeanDefinitionRegistry registry;注册器;registry默认实现 DefaultListableBeanFactory
    */
    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
   }
   catch (BeanDefinitionStoreException ex) {
    getReaderContext().error("Failed to register bean definition with name '" +
      bdHolder.getBeanName() + "'", ele, ex);
   }
   // 通知 注册事件已经完成;但是这个好像是个空实现,那么这个到底哪些场景会用到呢?TODO...
   getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
  }
 }

2二、BeanDefinitionReaderUtils


TODO... ###registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

public static void registerBeanDefinition(
   BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
   throws BeanDefinitionStoreException {
  // Register bean definition under primary name.
  String beanName = definitionHolder.getBeanName();
  registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
  // Register aliases for bean name, if any.
  String[] aliases = definitionHolder.getAliases();
  if (aliases != null) {
   for (String alias : aliases) {
    registry.registerAlias(beanName, alias);
   }
  }
 }

3三、DefaultListableBeanFactory


TODO

registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

/** 缓存所有的BeanDefinition */
 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
 /** 已注册的所有 BeanDefinition name*/
 private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);
 /** List of names of manually registered singletons, in registration order */
 /** 单例对象注册清单 */
 private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);
 /** Cached array of bean definition names in case of frozen configuration */
 private volatile String[] frozenBeanDefinitionNames;
@Override
 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 {
    /**
    *1.验证definition,如果getMethodOverrides().isNotEmpty() && getFactoryMethodName() != null 就抛异常;
    MethodOverrides在我们上一篇文章中的LookupOverride、ReplaceOverride被设置过;这行代码意思是如果设置了 MethodOverrides效果,则不能同时存在工厂方法;如下图中同时设置就会报错了
    *2.if (hasBeanClass()) {
      prepareMethodOverrides();
     }
    如果(this.beanClass instanceof Class) 这个beanClass在上一篇了解到,创建BeanDefinition的时候如果有ClassLoader就通过返回拿到Class对象;
    *3.bd的overrides做一些处理;
    */
    ((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()) {
    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
      "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
      "': There is already [" + oldBeanDefinition + "] bound.");
   }
   else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
    // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    if (this.logger.isWarnEnabled()) {
     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
       "' with a framework-generated bean definition: replacing [" +
       oldBeanDefinition + "] with [" + beanDefinition + "]");
    }
   }
   else if (!beanDefinition.equals(oldBeanDefinition)) {
    if (this.logger.isInfoEnabled()) {
     this.logger.info("Overriding bean definition for bean '" + beanName +
       "' with a different definition: replacing [" + oldBeanDefinition +
       "] with [" + beanDefinition + "]");
    }
   }
   else {
    if (this.logger.isDebugEnabled()) {
     this.logger.debug("Overriding bean definition for bean '" + beanName +
       "' with an equivalent definition: replacing [" + oldBeanDefinition +
       "] with [" + beanDefinition + "]");
    }
   }
   //覆盖注册
   this.beanDefinitionMap.put(beanName, beanDefinition);
  }
  else {
   //判断factory's 是否开始创建了;什么时候开始呢?TODO...回头单独分析
   if (hasBeanCreationStarted()) {
    // Cannot modify startup-time collection elements anymore (for stable iteration)
    synchronized (this.beanDefinitionMap) {
     //注册beanDefinition到map中
     this.beanDefinitionMap.put(beanName, beanDefinition);
     //下面这种处理为什么不直接this.beanDefinitionNames.add(beanName)?
     //大概是因为List是线程不安全的把;如果有线程在遍历,这里修改就会有问题了,所以直接新建一个list赋值过去
     List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
     updatedDefinitions.addAll(this.beanDefinitionNames);
     updatedDefinitions.add(beanName);
     this.beanDefinitionNames = updatedDefinitions;
     //判断 manualSingletonNames单例对象中是否存在相同的对象名,如果存在就表示不是单例对象了,就在manualSingletonNames中remove掉
     if (this.manualSingletonNames.contains(beanName)) {
      Set<String> updatedSingletons = new LinkedHashSet<String>(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);
  }
 }

AbstractBeanDefinition validate()

public void validate() throws BeanDefinitionValidationException {
  if (!getMethodOverrides().isEmpty() && getFactoryMethodName() != null) {
   throw new BeanDefinitionValidationException(
     "Cannot combine static factory method with method overrides: " +
     "the static factory method must create the instance");
  }
  if (hasBeanClass()) {
   prepareMethodOverrides();
  }
 }
/**
  * Validate and prepare the method overrides defined for this bean.
  * Checks for existence of a method with the specified name.
  * @throws BeanDefinitionValidationException in case of validation failure
  */
 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
  // Check that lookup methods exists. 查看是否有设置lookup
  MethodOverrides methodOverrides = getMethodOverrides();
  if (!methodOverrides.isEmpty()) {
   Set<MethodOverride> overrides = methodOverrides.getOverrides();
   synchronized (overrides) {
    for (MethodOverride mo : overrides) {
     prepareMethodOverride(mo);
    }
   }
  }
 }
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
  //查找这个beanClass的所有跟mo.getMethodName()相等的描述方法、接口数量
  int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
  if (count == 0) {
   throw new BeanDefinitionValidationException(
     "Invalid method override: no method with name '" + mo.getMethodName() +
     "' on class [" + getBeanClassName() + "]");
  }
  //如果只有一个 则更新overloaded的属性为false;
  else if (count == 1) {
   // Mark override as not overloaded, to avoid the overhead of arg type checking.
   //标记这个mo不是 重载,而是覆盖;避免参数类型检查的开销。默认是true
   mo.setOverloaded(false);
  }
 }

36.png

4四、总结

上面只是简单的分析了一下BeanDefinition的去处,发现BeanDefinition后来是注册到了DefaultListableBeanFactory中;这个存放了所有的BeanDefinition引用; 上面还有一些问题没有说清楚; 1.delegate.decorateBeanDefinitionIfRequired 修饰BeanDefinition分析? 2.hasBeanCreationStarted() 判断是否有bean一句开始创建了? 3.registerSingleton 注册单例分析? 4.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 这个通知事件怎么使用呢?

上面等下次有时间再单独分析;

相关文章
|
25天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
25天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
25天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
25天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
11天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
1天前
|
自然语言处理 数据处理 索引
mindspeed-llm源码解析(一)preprocess_data
mindspeed-llm是昇腾模型套件代码仓,原来叫"modelLink"。这篇文章带大家阅读一下数据处理脚本preprocess_data.py(基于1.0.0分支),数据处理是模型训练的第一步,经常会用到。
7 0
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
107 2
|
3月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
91 0
|
3月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
77 0
|
3月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
79 0

热门文章

最新文章

推荐镜像

更多