Spring 源码阅读 08:加载 BeanDefinition 的过程(解析阶段)

【Spring源码阅读】BeanDefinition原理与加载流程 BeanDefinition接口定义及其相关子类实现 在Spring容器初始化过程中,Spring会将配置文件中配置的Java类封装成一个个BeanDefinition。 BeanDefinition存储了具体代表Bean的类,并通过实现了AttributeAccessor接口定义了读写属性配置的相关方法。在基于xml配置Spring容器中,我们为某个Bean配置了具体的属性值,这些都根据name... 阅读详情

BeanDefinition 的解析

下面从int count = registerBeanDefinitions(doc, resource)这行代码入手,先找到registerBeanDefinitions方法的源码:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

下面罗列一下方法中的逻辑:

  1. 创建一个 BeanDefinitionDocumentReader 对象documentReader
  1. 获取 Spring 容器中已经注册的 BeanDefinition 的数量
  1. 调用documentReader的registerBeanDefinitions方法,初步分析这里完成了解析和向容器中注册 BeanDefinition 的过程。
  1. 通过简单运算得到本次注册的 BeanDefinition 的数量并返回。

这里主要关注一下步骤1和3。

documentReader的创建

首先简单看一下documentReader是如何创建的:

protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
   return BeanUtils.instantiateClass(this.documentReaderClass);
}
private Class<? extends BeanDefinitionDocumentReader> documentReaderClass =
      DefaultBeanDefinitionDocumentReader.class;

这里从createBeanDefinitionDocumentReader方法和documentReaderClass成员变量的代码可以看出,这里通过反射创建了一个 DefaultBeanDefinitionDocumentReader 类型的对象。

下面再看最重要的registerBeanDefinitions方法:

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   doRegisterBeanDefinitions(doc.getDocumentElement());
}

BeanDefinitionParserDelegate的创建

这里看到了一个名为doXXX的方法调用,应该就是这部分的核心逻辑了,这里传入的参数是doc.getDocumentElement(),代表的是 XML 文件中的beans标签。查看方法源码:

 /**
* Register each bean definition within the given root {  @code  <beans/>} element.
*/
@SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
   // Any nested <beans> elements will cause recursion in this method. In
   // order to propagate and preserve <beans> default-* attributes correctly,
   // keep track of the current (parent) delegate, which may be null. Create
   // the new (child) delegate with a reference to the parent for fallback purposes,
   // then ultimately reset this.delegate back to its original (parent) reference.
   // this behavior emulates a stack of delegates without actually necessitating one.
   BeanDefinitionParserDelegate parent = this.delegate;
   this.delegate = createDelegate(getReaderContext(), root, parent);

   if (this.delegate.isDefaultNamespace(root)) {
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         // We cannot use Profiles.of(...) since profile expressions are not supported
         // in XML config. See SPR-12458 for details.
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isDebugEnabled()) {
               logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                     "] not matching: " + getReaderContext().getResource());
            }
            return;
         }
      }
   }

   preProcessXml(root);
   parseBeanDefinitions(root, this.delegate);
   postProcessXml(root);

   this.delegate = parent;
}

这里先解释一下方法体中第一行和最后一行代码,这两行代码看起来是在开头将this.delegate成员变量赋值给了一个局部变量,在方法末尾在还原,在中间部分,会创建新的delegate来执行真正的工作。这么做的原因是,如果在配置文件中,一个beans标签中又嵌套了另一个beans标签,那么会递归调用这个方法,这两句代码其实是在处理每一层递归栈各自的状态。

在上面的方法源码中,先看delegate的创建:

protected BeanDefinitionParserDelegate createDelegate(
      XmlReaderContext readerContext, Element root, @Nullable BeanDefinitionParserDelegate parentDelegate) {

   BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
   delegate.initDefaults(root, parentDelegate);
   return delegate;
}

这里先知道delegate是 BeanDefinitionParserDelegate 类型的,从名字可以初步推断出,它是一个从 Document 中解析 BeanDefinition 的代理类,后面具体解析的时候,我们再做分析。

这个方法中最核心的部分是后面的三行代码:

preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);

其中,preProcessXml和postProcessXml两个方法的方法体是空的,且方法是protected修饰的,因此可以推断,这两个方法是留给子类的扩展点。

匹配标签解析的逻辑

下面重点看parseBeanDefinitions方法:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

从这里的代码可以大概看出,要真正开始对 Document 的内容进行解析了。

这里先简单介绍一下 Node 和 Element。Element 是 XML 中的一个标签,而 Node 是 XML 中的一个节点,节点可以是标签,也可以是标签的属性或者标签体中的文本内容。

接下来看第一行if判断语句delegate.isDefaultNamespace(root),判断一个元素是不是默认命名空间,先找到这个方法的具体内容:

public boolean isDefaultNamespace(Node node) {
   return isDefaultNamespace(getNamespaceURI(node));
}
public boolean isDefaultNamespace(@Nullable String namespaceUri) {
   return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
}
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

根据以上的三段代码分析,这里的逻辑是,获取到元素的namespaceUri如果它是空的,或者是http://www.springframework.org/schema/beans,那么它就是默认命名空间,也就是默认标签。

回到上面的parseBeanDefinitions方法,我们可以总结这段逻辑:

  • 判断当前处理的是不是默认标签,就执行自定义标签的解析逻辑
  • 遍历当前标签的所有自节点
  • 如果自节点也是标签的话,判断它是不是默认标签,如果是就执行默认标签的解析逻辑,如果不是则执行自定义标签的解析逻辑

这里的默认标签指的是beans、bean等标签,除了默认标签以外,还有很多你一定见过的自定义标签,比如<context:component-scan/>等。之后的分析只考虑分析默认标签的情况。

在进入到默认标签处理逻辑parseDefaultElement方法中:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

来到这里以后,会根据标签的名称来执行不同的解析逻辑。

如果是beans标签,那么又会执行前面介绍过的doRegisterBeanDefinitions方法,这也是前面提到这个方法可能会递归调用的原因。不过根据前面的代码分析,我们这里要解析的是bean标签的内容,因此会进入到processBeanDefinition(ele, delegate);这个方法调用中。

bean标签元素信息的解析

我们继续深入代码:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

这里可以看到,最终解析的工作还是delegate来完成的,解析的结果是一个 BeanDefinitionHolder 的对象bdHolder,根据名称推断,这个对象会持有解析出的 BeanDefinition。之后,在try语句块中,将解析的结果注册到容器中。

注册的具体过程我们放到下一篇,接下来看解析的过程。进入delegate的parseBeanDefinitionElement方法:

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}

调用重载方法:

@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   // 第1部分
   String id = ele.getAttribute(ID_ATTRIBUTE);
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

   // 第2部分
   List<String> aliases = new ArrayList<>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }

   // 第3部分
   String beanName = id;
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isTraceEnabled()) {
         logger.trace("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }

   // 第4部分
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
         /* 省略,因为我们目前分析的流程中,beanName 不可能为空 */
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}

这里我通过注释将代码分成了4部分,下面分别来介绍这4部分的逻辑:

  1. 从 XML 标签中获取其中的id和name属性。
  2. 处理别名,因为 Spring 允许给 Bean 配置多个名称,这一步就是解析出这些名称,放到aliases数组中。
  3. 将id作为 Bean 在容器中的唯一名称,如果没有给 Bean 配置id,则从aliases中取出第一个作为 Bean 的名称,并检查名称的唯一性。
  4. 解析 Bean 对应的标签,并得到 AbstractBeanDefinition 类型的结果,如果结果不为空,则封装 BeanDefinitionHolder 对象并返回。

bean标签元素内容的解析

接下来,在进入到parseBeanDefinitionElement方法中,查看 Bean 对应的标签解析的过程:

@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {

   this.parseState.push(new BeanEntry(beanName));

   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);

      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

      parseMetaElements(ele, bd);
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

      parseConstructorArgElements(ele, bd);
      parsePropertyElements(ele, bd);
      parseQualifierElements(ele, bd);

      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));

      return bd;
   }
   /* 省略异常处理逻辑 */
   finally {
      this.parseState.pop();
   }

   return null;
}

这里的主要流程在try语句块中,我分别来介绍一下这些代码都干了什么:

  • 第一行代码中,通过createBeanDefinition方法创建了一个AbstractBeanDefinition。
  • 接下来的两行代码,解析了bean标签中的各种属性,并封装到了bd中。(其中的代码比较长且逻辑简单,感兴趣的话可以自行查看)
  • 接下来的6行代码,分别解析了bean的各种子标签的信息,并封装到bd中,这些子标签包括meta、lookup-method、replaced-method、constructor-arg、property、qualifier,关于这些子标签的信息不在本文讨论范围,不过你应该对它们都很熟悉。
  • 最后添加了一些附加信息之后将bd返回。

BeanDefinition 的创建

这里我们再看一下createBeanDefinition方法是如何创建 BeanDefinition 的:

protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
      throws ClassNotFoundException {
   return BeanDefinitionReaderUtils.createBeanDefinition(
         parentName, className, this.readerContext.getBeanClassLoader());
}

这里在继续查看BeanDefinitionReaderUtils.createBeanDefinition的源码:

public static AbstractBeanDefinition createBeanDefinition(
      @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
   GenericBeanDefinition bd = new GenericBeanDefinition();
   bd.setParentName(parentName);
   if (className != null) {
      if (classLoader != null) {
         bd.setBeanClass(ClassUtils.forName(className, classLoader));
      }
      else {
         bd.setBeanClassName(className);
      }
   }
   return bd;
}

这里可以看到,我们实际创建的 BeanDefinition 的类型是 GenericBeanDefinition。

后续

至此,将 Document 解析成 BeanDefinition 的过程,就分析到这里,对于bean标签的子标签的解析过程,将不再分析,因为其中的内容比较多,且逻辑简单,其核心任务都是将标签中解析到的信息封装到 BeanDefinition 当中。至此我们已经了解了整个过程的逻辑,想了解更细节的解析过程,可以自己继续深入阅读代码。

AI学习指南RAG篇(19)-API调用与集成 通过上述API调用示例,您可以方便地将RAGFlow与其他系统集成,实现数据集管理、文档处理、会话管理等功能。希望本文的介绍能帮助您更好地理解和使用RAGFlow的API。 阅读详情

相关推荐

MiniMax H3本地部署实战:ComfyUI整合包安装与提速插件验证指南

在AIGC工具链快速演进的当下,本地部署内容生成模型成为许多创作者和开发者的关注焦点。本地部署意味着数据不出本机、可按需定制工作流,还能规避云端排队与外部依赖,其核心价值在于为内容生产提供可控、私密且可编程的生成环境。ComfyUI作为模块化节点式AI绘画工具,凭借灵活的工作流编排和API接口能力,成为承载这类模型的热门平台。MiniMax H3作为支持文本、参考图等多种输入的内容生成模型,与ComfyUI结合后,既适合个人进行概念验证,也能用于团队私有化流程搭建。实际落地过程中,中文整合包显著降低了环境配

weixin_29042035的博客 298

spring对xml文件进行加载bean过程初步解析

以下是一段简单的通过类路径下的test.xml文件加载bean获得BeanFactory的代码:(对student进行依赖注入) BeanFactory bf = new XmlBeanFactory(new ClassPathResource("test.xml")); 其中new ClassPathResource()为内置的解析xml文件,进行封装底层资源。 通过源...

大鹏的博客 2464

十、强势股的起爆点:第三类买点的实战精解

本文深入解析强势股交易中的第三类买点(三买)实战技巧,涵盖两种经典模式:突破首个中枢后的回踩和底部反转后的直接脱离下跌中枢。通过详细案例和数据分析,揭示三买在捕捉主升浪起爆点时的黄金信号作用,帮助投资者优化风险收益比,提升短线交易成功率。

weixin_30260191的博客 314

Spring源码解析(4)——注册BeanDefinition

回顾上篇 上篇文章解析配置文件我们已经分析完了配置文件解析过程,这个时候Spring已经创建了一个BeanDefinition并且将封装到了BeanDefinitionHolder中。接下来我们就接着分析注册BeanDefinition的过程。 分析源码实现 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = d

tack_back的博客 591

用Simulink对Carsim车辆进行档位控制

用Simulink对Carsim车辆进行档位控制一、carsim中的档位设置为开环控制二、在Constant目录下面选取一个选项并重新命名为constant :0 Gear三、双击进去设置常量为 0四、输入和输出IO通道五、验证 :输入 为 3 档 ----- 输出 为 3!六、参考 一、carsim中的档位设置为开环控制 二、在Constant目录下面选取一个选项并重新命名为constant :0 Gear 三、双击进去设置常量为 0 四、输入和输出IO通道 五、验证 :输入 为 3 档 -

qq_42027654的博客 2603

2017阿里内推笔试题--算法工程师(运筹优化)

2017阿里内推笔试题–算法工程师(运筹优化)题目沐哲是一个菜鸟仓库的一个拣货员,但他有非常个怪异的习惯。每次拣货的重量都要比之前拣的一个轻,每次拣到货后都可以得到1块钱,沐哲想知道这样最多能赚多少钱 32 34 7 33 21 2 13 12 3 11 26 36 16 30 22 1 24 14 20 23 25 5 19 29 27 15 9 17 31 4 6 18 8 10 3

shawpan的专栏 1万+

【Spring源码】IOC容器实现(3)--BeanDefinition的载入和解析

前言 Github:https://github.com/yihonglei/thinking-in-spring BeanDefinition的载入和解析 上文分析了BeanDefiniton的Resource定位过程: Spring源码--IOC容器实现(2)--BeanDefinition的Resource定位 这篇文章分析下BeanDefinition信息的载入过程。 载入过程...

yhl_jxy的博客 1232

网络安全 —— 实验(基于华为eNSP模拟器)

8. 实验八 —— 通过路由的远程管理(基于实验七的基础配置)8. 实验八 —— 通过路由的远程管理(基于实验七的基础配置)6. 实验六 —— 交换机的远程控制(直接控制和间接控制)6. 实验六 —— 交换机的远程控制(直接控制和间接控制)5. 实验五 —— 将交换机作为PC端通过交换机相连。5. 实验五 —— 将交换机作为PC端通过交换机相连。4. 实验四 —— 两个PC机通过两台交换机相连。2. 实验二 —— 两个PC机通过交换机相连。2. 实验二 —— 两个PC机通过交换机相连。

这个家伙看起来很懒,只想把你留下来哦 9343

项目启动报 Invalid bean definition with name 的原因及解决办法

SpringBoot项目启动,控制台报错:Invalid bean definition with name...首先要查看一下你的接口或者配置类,带有 @Component或@Configuration 的配置类是否被重复定义。

hkl_Forever的博客 3万+

MuJoCo与Isaac Sim的无缝对接:利用USD导出功能实现强化学习场景的跨平台迁移

本文详细介绍了如何通过USD导出功能实现MuJoCo与Isaac Sim的无缝对接,助力强化学习场景的跨平台迁移。文章解析了USD格式的核心优势,包括分层合成、物理属性继承和时间轴动画,并提供了从MJCF到USD的完整转换流程及在Isaac Sim中的高级应用技巧,帮助开发者高效迁移和优化强化学习环境。

weixin_29073241的博客 519

MIKE水动力笔记5_建立水动力模型

前文已经讲了如何制作网格文件(.mdf文件),这一博文就讲如何建立水动力模型。

晏长街的博客 3万+

BeanDefinition的注册

上节完成对BeanDefinition的解析分析后,下面继续了解BeanDefinition的注册过程 main方法 public static void main(String[] args) { //1.资源定位 Resource resource = new ClassPathResource("bean.xml"); //2.创建IOC容器,这里使用DefaultListableBeanFactory作为IOC容器 DefaultListableBeanFactory default

保质期已过 592

SPI 总线信号完整性与时序一致性测试

SPI总线测试的核心目标是验证其电气与时序行为是否满足芯片规格要求,确保通信可靠性

硬核科技 330

spring源码系列(三)——beanDefinition(1)

如果想系统的学习spring源码那么第一个需要搞明白的知识便是spring当中的BeanDefinition——spring bean的建模对象; 那么什么是spring bean的建模对象呢?一言概之就是把一个bean实例化出来的模型对象?有人会问把一个bean实例化出来有class就行了,Class也就是我们通常说的类对象就是一个普通对象的建模对象那么为什么spring不能用Class来建立b...

java_lyvee的专栏 5万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Spring高手之路16——解析XML配置映射为BeanDefinition的源码

本文提供了深入Spring源码的透彻解析,从XML配置文件的加载开始,步入了Spring的内部世界。通过细致剖析setConfigLocations、refresh和loadBeanDefinitions等方法的实现,揭示了Bean从定义到注册的整个生命周期。

卓越无关环境,保持空杯心态——靡不有初,鲜克有终 9792

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

spring源码阅读之bean加载过程(一)

而obtainFreshBeanFactory()方法里有下面一行,发现最终用的BeanFactory为DefaultListableBeanFactory,是不是有点眼熟了,没错,就是第一个测试用例中使用的,那后面的过程就是一致的了,下图中画出来的两句跟第一个测试用例的两句表达的是一个意思,obtainFreshBeanFactory()方法执行完之后在factory的beanDefinitionMap里已经存了xml里有的数据,即第一个类图里面的流程都run了一遍。

京东科技开发者 1089

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Spring源码阅读——BeanDefinition注册的过程

本篇文记录一下从location路径 -> BeanDefinition注册的过程. 以XML方式为例子. 看本文前需要读者已经明白如下知识: BeanDefinition接口,Resource接口,ResourceLoader接口,BeanFactory接口,ApplicationContext接口,我会在另一文中简单介绍一下这些. 一、什么是BeanDefinition的注册 Bea...

困兽的博客 636

【Spring专题】Spring之Bean的生命周期源码解析——阶段一(扫描生成BeanDefinition)

Spring最重要的功能就是帮助程序员创建对象(也就是IOC),而启动Spring就是为创建Bean对象做准备,所以我们先明白Spring到底是怎么去创建Bean的,也就是先弄明白Bean的生命周期。Bean的生命周期就是指:在Spring中,一个Bean是如何生成的,如何销毁的。/*** 创建一个新的AnnotationConfigApplicationContext,扫描给定包中的组件,为这些组件注册bean定义,并自动刷新上下文。

qq_32681589的博客 1896

Spring 源码阅读 06:加载 BeanDefinition 的过程(准备阶段)

方法提虽然长,但是我们稍微仔细看一下就会发现,其实这里核心就做了一件事,就是将方法参数中传递进来的配置文件路径,加载成了一个 Resource 对象,然后对这个 Resource 对象调用了另外一个以 Resource 类型为参数的。在这个方法的参数列表中,一个是用 Resource 的输入流封装成的 InputSource,用于 XML 的读取,另一个是 Resource 对象本身。这里又调用了一个重载方法,并且我们留意到,增加了第二个参数,传入值为空。中,而上面我们看过的几个同名的重载方法都定义在。

知识分享官 343

Spring 源码阅读 09:加载 BeanDefinition 的过程(注册阶段)

因此,这里的判断是为了确保配置信息没有出现冲突。传入方法的参数,一个是之前解析道的 BeanDefinitionHolder,另一个其实就是我们最初创建的 BeanFactory(这里为什么是最初创建的 BeanFactory?这里针对配置了 MethodOverrides 的 BeanDefinition,从 Bean 对应的类中获取同名的方法,也就是要被覆盖的方法。就是我们起初创建的 BeanFacoty,之前涉及到的流程已经很多了,这里再捋一下起初创建的 BeanFacoty 是怎么到这儿的。

java_lujj的博客 440

Spring 源码阅读 07:加载 BeanDefinition 的过程(资源加载阶段)

我们之前说到,在 XML 文件被解析的时候,会根据其对应的约束文件,对 XML 进行校验,确保它是符合预设的模式的。Spring 的 XML 配置文件,对内容和格式都有严格的约束,如果配置文件不符合这些约束要求,就会导致 Spring 初始化失败,因此,在初始化之前,Spring 需要对这些文件进行校验。方法中的几个方法参数,从方法体中的代码看出,这几个参数传入的具体信息会影响 XML 解析的配置,其中,前三个参数的类型都属于。的封装,它其实就代表了要被解析的 XML 的输入流。

知识分享官 480

【Spring源码】XML配置加载BeanDefinition的骨架

本文深入解析了Spring框架如何将XML配置文件加载为BeanDefinition的核心流程。首先回顾了XML验证模式的检测机制,然后重点剖析了BeanDefinition解析的骨架结构。关键点包括:1) 通过BeanDefinitionDocumentReader读取XML文档;2) 使用delegate模式实现嵌套beans标签的属性隔离;3) 采用三步走策略(预处理→解析→后处理)完成解析;4) 支持自定义标签的扩展机制。文章通过源码分析和类比说明,揭示了Spring如何将XML标签转换为BeanD

weixin_44250106的博客 988

Spring源码解析之BeanDefinition

Spring源码解析之BeanDefinition通过阅读本文你能获得什么为什么要学习BeanDefinitionBeanDefinition在Spring中的作用BeanDefinition的定义BeanDefinition的类型BeanDefinition的实战 通过阅读本文你能获得什么 1、什么是BeanDefinition 2、怎么用BeanDefinition定制化开发 为什么要学习BeanDefinition BeanDefinition看名称可以大致明白是用来描述spring中bean的

azhida的博客 823

Spring源码分析,BeanDefinition加载过程

1.简介 Spring的启动分为关键步骤,首先是将配置文件中定义的<bean>信息加载到BeanDefintionRegistry中。然后通过BeanFactory中的getBean方法来将BeanDefinition进行实例化,开始整个bean的生命周期。 2.BeanDef...

chouzou5531的博客 219

Spring官网阅读(四)BeanDefinition(上)

前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等。这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Spring中非常基础的一块内容,也是我们阅读源码的基石。本文主要涉及到官网中的1.3及1.5中的一些补充知识。同时为我们1.7小节中BeanDefinition的合并做一些铺垫 BeanDefini...

做一个认真的程序员 5698
上一篇: 手把手教你SpringBoot集成SFTP客户端实现文件上传下载
下一篇: 深入剖析Spring Boot 的SPI机制
java_lujj
博客等级 码龄4年 18粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值