Spring 源码学习笔记(二)之Bean标签默认属性的解析

分析调用栈

Spring 通过读取 xml 配置文件注册 bean ,通过工厂可以获取注册的 bean,示例代码:

XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Object main = beanFactory.getBean("main");
System.out.println(main);

配置文件 applicationContext.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="main" class="com.pine.Main" />
</beans>

在上述 XmlBeanFactory 中有一个解析器,通过该解析器解析 xml 配置文件:
image.png

BeanDefinition 类型是 bean 标签在 JVM 中的存在形式

进入loadBeanDefinitions方法中,重点是331行开始的这一段:

try {
    // 获取配置文件的输入流
    InputStream inputStream = encodedResource.getResource().getInputStream();
    try {
        // InputSource 用于 xml 解析,类似工具类
        InputSource inputSource = new InputSource(inputStream);
        if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
        }
        // 执行解析逻辑
        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
    finally {
        inputStream.close();
    }
}

在 Spring 源码中有一个惯例,就是 do… 方法一般是真正执行具体逻辑的方法

继续进入 doLoadBeanDefinitions 方法,可以看到是一个 try 后面很多 catch ,只需要关注 try 里的内容就可以了,catch里无非是一些异常处理。这个方法中需要关注的是 registerBeanDefinitions 方法,继续进入它的重载方法,再来到 doRegisterBeanDefinitions 方法。
这个方法中主要有两个部分,上面的 if 块和下面的 parseBeanDefinitions 方法。 if 块的作用是处理不同的 profile (多环境),parseBeanDefinitions 才是解析标签。
这个方法的注释及方法体如下:

/**
 * Parse the elements at the root level in the document:
 * "import", "alias", "bean".
 * @param root the DOM root element of the document
 */
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);
    }
}

bean 标签是 Spring 中默认自带的元素,所以先看 parseDefaultElement 方法,再进入 processBeanDefinition 方法,继续来到 parseBeanDefinitionElement 方法。

分析解析方法

至此,终于来到了最终执行解析逻辑的方法!
1)首先是前两行:

// 解析 id 属性
String id = ele.getAttribute(ID_ATTRIBUTE);
// 解析 name 属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

很浅显易懂,就是解析 id 和 name 这两个属性。

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)接着兼容了 bean 标签中没有 id 的情况(这里也说明了为什么 bean 可以不指定 id):

String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    beanName = aliases.remove(0);
    ……
}

4)然后是当前方法的重载方法 parseBeanDefinitionElement,
4.1)这个方法中首先解析了 class 和 parent 属性:

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);
}

4.2)然后是 lookup-method、replaced-method 等子标签:

// meta
parseMetaElements(ele, bd);
// lookup-method
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
// replaced-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

// constructor-arg
parseConstructorArgElements(ele, bd);
// property
parsePropertyElements(ele, bd);
// qualifier
parseQualifierElements(ele, bd);

5)最后是一个 if 块,这个 if 块主要是处理了 id , name 都为空的情况,会根据算法为当前 bean 生成一个名字,这里不细究。

这样,就搞清楚了 xml 配置文件中 bean 标签是如何解析的。

欢迎关注微信公众号co松柏一起学习交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/527240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通过网络api获取日期对应的节假日信息

网络接口获取链接&#xff1a;免费节假日API_原百度节假日API HolidayJudge.h #pragma once#include <QtWidgets/QWidget> #include "ui_HolidayJudge.h"enum DATESTATE {WORK0,//工作日DAYOFF,//休息日HOLIDAY//节假日 };class HolidayJudge : public QWidg…

F5防火墙如何应对恶意攻击?一文搞懂

当前&#xff0c;5G网络模糊了安全防护边界&#xff0c;加速了全球网络攻击升级&#xff0c;攻防对抗变得日益激烈&#xff0c;导致传统网络安全防护措施越来越难以有效预测和应对潜在威胁。面对复杂部署环境&#xff0c;企业的安全团队正在努力寻找一致性的安全防护和可见性策…

谷歌浏览器用不了怎么办?

打开谷歌浏览器点击右上角的三个点 &#xff0c; 点击设置 在搜索引擎里面把这个改成百度 然后越狱登录你的谷歌账号就可以用了 我个人用的越狱软件是r2rayn &#xff0c; 浏览器上面可以搜索的 默认浏览器那里可以设置成谷歌

IP网络对讲广播系统审计

前言 这个系统是前两年在一个内网遇到的&#xff0c;当时顺手试了一个admin登陆之后再没有然后了&#xff0c;最近发现有大佬分享关于这个系统的漏洞&#xff0c;于是就把自己当初看的几个漏洞分享一下&#xff0c;系统比较简单&#xff0c;漏洞点很多&#xff0c;不要做坏事哦…

C++练级之路——类和对象(上)

1、类的定义 class 类名{//成员函数 //成员变量}; class为定义的关键字&#xff0c;{ }内是类的主体&#xff0c;注意后面的 ; 不要忘了 类体中的内容成为类的成员&#xff0c;类中的变量为成员变量或类的属性&#xff0c;类中的函数为成员函数或类的方法&#xff0c; 类的两种…

【Shell语言学堂】Shell 脚本练习1

Shell 脚本练习 shell语言实战 Shell 脚本练习&#x1f4a7;CSDN划过手的泪滴t现有一个脚本可传入n个参数&#xff0c;要求在脚本中实现在终端输出第n个参数之前的所有参数(不包含第n个参数)编写一个计算bmi体质指数的脚本&#xff0c;该脚本需要用户输入身高和体重信息&#x…

单调栈(LeetCode-下一个更大元素)

每日一题 今天刷到了一道用到单调栈来解决的题目&#xff0c;想到自己没有总结过单调栈的知识点&#xff0c;因此想总结一下。 介绍 什么是单调栈&#xff1f; 单调栈的定义其实很简单&#xff0c;所谓单调栈就是指一个单调递增或是单调递减的栈。 那单调栈有什么用呢&#x…

CSS层叠样式表学习(基础选择器)

&#xff08;大家好&#xff0c;今天我们将继续来学习CSS&#xff08;2&#xff09;的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 二、CSS基础选择器 2.1 CSS选择器的作用 2.2 选择器分类 2.3 标签选择器 2.…

Windows系统下安装java开发环境所需的JDK开发工具包

目录 一、JDK开发工具包下载二、安装三、环境变量配置3.1 添加安装包路径3.2 添加lib路径3.3 添加bin目录 四、检查是否安装成功五、总结 一、JDK开发工具包下载 官网地址&#xff1a;JDK下载 打开网址后有多个版本的JDK&#xff0c;学者根据自己电脑需求选择对应版本下载。如…

精酿啤酒:传统酿造与现代工艺的结合

在啤酒酿造领域&#xff0c;传统酿造与现代工艺的结合是提品质和生产效率的重要途径。Fendi Club啤酒在酿造过程中&#xff0c;巧妙地将传统酿造工艺与现代技术相结合&#xff0c;为消费者带来了品质的啤酒体验。 Fendi Club啤酒注重传统的天然原料选择。他们坚持使用大麦、啤酒…

免费云服务器汇总,最长永久免费使用

随着云计算技术的快速发展&#xff0c;越来越多的企业和个人开始将业务迁移到云端。云服务器作为云计算的重要组成部分&#xff0c;以其灵活、高效、可扩展等特点受到广泛关注。然而&#xff0c;许多人在初次接触云服务器时&#xff0c;可能会对高昂的价格望而却步。为了帮助大…

day76 jquery

知识点: 1 在HTML中引入jQuery 2 jQuery中就绪函数 3 jQuery中选择器 4 使用jQuery获取表单元素的值 及标签中间的内容 5 jQuery中获取标签属性 6 jQuery设置和获取标签样式 ----------------------------------- 一 在HTML中引入jQuery 1 1) 把jQue…

工作这么久,你有测试思维了吗?

在如今竞争激烈的职场中&#xff0c;拥有测试思维已成为一个不可或缺的技能。无论你是从事软件开发、项目管理还是市场营销等各行各业&#xff0c;测试思维都能够帮助你更好地解决问题、提高工作效率以及保障质量。然而&#xff0c;工作时间的长短并不代表一个人是否具备测试思…

python ConfigParser:Python 标准库,ini 文件解析器

大家好&#xff01;在进行接口自动化工作时&#xff0c;配置文件是非常常见和重要的一部分。Python 提供了一个强大的标准库——ConfigParser&#xff0c;用于解析和处理 INI 文件。在本文中&#xff0c;我们将介绍如何使用 ConfigParser 来读取和操作 INI 文件&#xff0c;并提…

【Linux进阶之路】ARP欺骗实验

正文 话不多说&#xff0c;直接干&#xff01; 首先我们需要准备一下环境&#xff0c;先配置VMARE&#xff0c;然后下载KALI的虚拟机。 详细的安装教程视频&#xff1a;点击跳转&#xff0c;下载KALI可能要半个小时&#xff0c;中间可以看个剧玩个游戏缓一缓。 配置好之后&am…

ArcGIS和ArcGIS Pro快速加载ArcGIS历史影像World Imagery Wayback

ArcGIS在线历史影像网站 World Imagery Wayback(网址:https://livingatlas.arcgis.com/wayback/)提供了数期历史影像在线浏览服务,之前不少自媒体作者在文中宣称其能代表Google Earth历史影像。 1、一点对比 (1)同一级别下的版本覆盖面 以下述区域为例,自2014年2月20…

提升自媒体写作效率:7款必备工具推荐! #知识分享#媒体#AI写作

我们做自媒体运营&#xff0c;想要快速的创作内容&#xff0c;提供文章的创作速度是我们的目标&#xff0c;我们别的大佬可以很快地就创作出一篇内容&#xff0c;而自己墨迹半天确出不了一个字呢&#xff1f;其实这关乎到创作技巧&#xff0c;下面小编就跟大家分享如何利用自媒…

OneFlow深度学习框架:技术优势与功能特点

文章目录 一、概要二、核心技术优势2.1、分布式训练2.2、极致性能2.3、端到端的智能数据平台2.4、开放灵活的算法支持2.5、跨平台支持 三、功能特点四、OneFlow与TensorFlow对比四、安装OneFlow五、总结 一、概要 OneFlow是一款基于Python的开源深度学习框架&#xff0c;旨在实…

简介有向无环图DAG

Sui创纪录的每秒交易量部分归功于数学构造&#xff0c;即有向无环图&#xff08;Directed Acyclic Graph&#xff0c;DAG&#xff09;&#xff0c;该构造通过以最高效的方式处理交易来加速网络交易&#xff0c;而不是按照先来先服务的线性进展。 区块链是设计用于确保数据完整…

【简单讲解下Lisp的学习历程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…