当前位置: 首页 > article >正文

Spring如何通过XML注册Bean

在上一篇当中我们完成了对三种资源文件的读写

上篇内容:Spring是如何实现资源文件的加载
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@Test  
public void testClassPathResource() throws IOException {  DefaultResourceLoader defaultResourceLoader = new DefaultResourceLoader();  Resource resource = defaultResourceLoader.getResource("classpath:hello.txt");  InputStream inputStream = resource.getInputStream();  String read = IoUtil.readUtf8(inputStream);  System.out.println(read);  
}

对于单一的资源文件我们要想将其中的配置解析为Bean需要经过以上几步

  • 获取默认的资源文件加载器
  • 加载指定资源文件
  • 获取输入流对象
  • 解析为Bean

如何解析XML文件

将XML文件配置解析为BeanDefinition,需要涉及到的有BeanDefinition的注册功能与ResourceLoad资源文件加载器

这里我们就可以定义一个类,同时实现以上两者

首先为了扩展性我们先定义一个BeanDefinitionReader接口,我们来想一下不只是XML方式来注册Bean,在Spring当中还可以通过注解等方式,那我们就需要抽象一个通用接口定义通用方法,供子类来实现就行了

public interface BeanDefinitionReader {  /**  * 获取BeanDefinitionRegister实例。  * @return BeanDefinitionRegister 用于注册BeanDefinition的实例  */  BeanDefinitionRegister getRegistry();  /**  * 获取ResourceLoader实例。  * @return ResourceLoader 用于加载资源的实例  */  ResourceLoader getResourceLoad();  /**  * 根据指定的资源位置加载BeanDefinition。  * @param location 资源的位置,通常为文件路径或URL  */    void loadBeanDefinitions(String location);  /**  * 根据指定的多个资源位置加载BeanDefinition。  * @param locations 资源的位置数组,通常为文件路径或URL数组  */  void loadBeanDefinitions(String[] locations);  /**  * 根据指定的Resource对象加载BeanDefinition。  * @param resource 资源对象,包含具体的资源信息  */  void loadBeanDefinitions(Resource resource);  
}

之后我们还可以定义一个抽象类,实现通用方法的基本逻辑

public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader{  private ResourceLoader resourceLoader;  private final BeanDefinitionRegister beanDefinitionRegister;  /**  * beanDefinitionRegister是用来注册BeanDefinition使用的  * 其子类DefaultListableBeanFactory实现了beanDefinitionRegister与BeanFactory  * 可以通过DefaultListableBeanFactory获取、创建Bean  * @param beanDefinitionRegister 用于注册BeanDefinition的实例  */  protected AbstractBeanDefinitionReader(BeanDefinitionRegister beanDefinitionRegister) {  this.resourceLoader = new DefaultResourceLoader();  this.beanDefinitionRegister = beanDefinitionRegister;  }  /**  * 根据指定的多个资源位置加载BeanDefinition。  *  * @param locations 资源的位置数组,通常为文件路径或URL数组  */  @Override  public void loadBeanDefinitions(String[] locations) {  for (String location : locations) {  loadBeanDefinitions(location);  }  }  /**  * 获取BeanDefinitionRegister实例。  *  * @return BeanDefinitionRegister 用于注册BeanDefinition的实例  */  @Override  public BeanDefinitionRegister getRegistry() {  return beanDefinitionRegister;  }  /**  * 获取ResourceLoader实例。  *  * @return ResourceLoader 用于加载资源的实例  */  @Override  public ResourceLoader getResourceLoad() {  return resourceLoader;  }  public void setResourceLoader(ResourceLoader resourceLoader) {  this.resourceLoader = resourceLoader;  }  
}

现在我们就可以完成对于XML文件的具体解析逻辑了

public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {  public static final String BEAN_ELEMENT = "bean";  public static final String PROPERTY_ELEMENT = "property";  public static final String ID_ATTRIBUTE = "id";  public static final String NAME_ATTRIBUTE = "name";  public static final String CLASS_ATTRIBUTE = "class";  public static final String VALUE_ATTRIBUTE = "value";  public static final String REF_ATTRIBUTE = "ref";  /**  * beanDefinitionRegister是用来注册BeanDefinition使用的  * 其子类DefaultListableBeanFactory实现了beanDefinitionRegister与BeanFactory  * 可以通过DefaultListableBeanFactory获取、创建Bean  *     * @param beanDefinitionRegister 用于注册BeanDefinition的实例  */  public XmlBeanDefinitionReader(BeanDefinitionRegister beanDefinitionRegister) {  super(beanDefinitionRegister);  }  /**  * 根据指定的资源位置加载BeanDefinition。  *  * @param location 资源的位置,通常为文件路径或URL  */    @Override  public void loadBeanDefinitions(String location) {  // 通过ResourceLoad获取到Resource  ResourceLoader resourceLoad = getResourceLoad();  Resource resource = resourceLoad.getResource(location);  this.loadBeanDefinitions(resource);  }  /**  * 根据指定的Resource对象加载BeanDefinition。  *  * @param resource 资源对象,包含具体的资源信息  */  @Override  public void loadBeanDefinitions(Resource resource) {  try {  InputStream inputStream = resource.getInputStream();  try {  doLoadBeanDefinitions(inputStream);  }finally {  inputStream.close();  }  } catch (Exception e) {  throw new RuntimeException(e);  }  }  protected void doLoadBeanDefinitions(InputStream inputStream) throws Exception {  Document document = XmlUtil.readXML(inputStream);  Element root = document.getDocumentElement();  NodeList childNodes = root.getChildNodes();  for (int i = 0; i < childNodes.getLength(); i++) {  if (childNodes.item(i) instanceof Element) {  if (BEAN_ELEMENT.equals(((Element) childNodes.item(i)).getNodeName())) {  //解析bean标签  Element bean = (Element) childNodes.item(i);  String id = bean.getAttribute(ID_ATTRIBUTE);  String name = bean.getAttribute(NAME_ATTRIBUTE);  String className = bean.getAttribute(CLASS_ATTRIBUTE);  Class<?> clazz = Class.forName(className);  //id优先于name  String beanName = StrUtil.isNotEmpty(id) ? id : name;  if (StrUtil.isEmpty(beanName)) {  //如果id和name都为空,将类名的第一个字母转为小写后作为bean的名称  beanName = StrUtil.lowerFirst(clazz.getSimpleName());  }  BeanDefinition beanDefinition = new BeanDefinition(clazz);  for (int j = 0; j < bean.getChildNodes().getLength(); j++) {  if (bean.getChildNodes().item(j) instanceof Element) {  if (PROPERTY_ELEMENT.equals(((Element) bean.getChildNodes().item(j)).getNodeName())) {  //解析property标签  Element property = (Element) bean.getChildNodes().item(j);  String nameAttribute = property.getAttribute(NAME_ATTRIBUTE);  String valueAttribute = property.getAttribute(VALUE_ATTRIBUTE);  String refAttribute = property.getAttribute(REF_ATTRIBUTE);  Object value = valueAttribute;  if (StrUtil.isNotEmpty(refAttribute)) {  value = new BeanReference(refAttribute);  }  PropertyValue propertyValue = new PropertyValue(nameAttribute, value);  beanDefinition.getPropertyValues().addPropertyValue(propertyValue);  }  }  }  getRegistry().registerBeanDefinition(beanName, beanDefinition);  }  }  }  }  
}

写一个测试来实现该逻辑

@Test  
public void testXmlResourceReader(){  DefaultListableBeanFactory factory = new DefaultListableBeanFactory();  XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(factory);  xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");  People person = (People) factory.getBean("person");  System.out.println(person);  
}

相关文章:

Spring如何通过XML注册Bean

在上一篇当中我们完成了对三种资源文件的读写 上篇内容&#xff1a;Spring是如何实现资源文件的加载 Test public void testClassPathResource() throws IOException { DefaultResourceLoader defaultResourceLoader new DefaultResourceLoader(); Resource resource …...

理解 `#pragma pack`:C/C++内存对齐的钥匙

引言&#xff1a;为什么我的网络程序收发的数据总是错位&#xff1f; 在网络编程中&#xff0c;你是否遇到过这样的困惑&#xff1a;明明发送方和接收方的结构体定义完全一样&#xff0c;但解析出来的数据却乱七八糟&#xff1f;这很可能是因为内存对齐在作祟。今天我们就来深…...

开源键鼠共享软件的“爱恨情仇“:Deskflow、InputLeap与Barrier的演化史

开源键鼠共享软件的"爱恨情仇"&#xff1a;Deskflow、InputLeap与Barrier的演化史 一、血脉渊源&#xff1a;从Synergy到三足鼎立 这三款软件的起源都与 Synergy 这款商业软件密切相关&#xff1a; ‌2001年‌&#xff1a;Synergy开创软件化KVM先河‌2017年‌&…...

【Python核心库实战指南】从数据处理到Web开发

目录 前言&#xff1a;技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块对比 二、实战演示环境配置要求核心代码实现&#xff08;5个案例&#xff09;案例1&#xff1a;NumPy数组运算案例2&#xff1a;Pandas数据分析…...

运维:概念、模式与硬件基础

一、运维概述&#xff1a;从网管到智能运维的进化之路 1. 运维岗位的定义 IT运维管理是保障企业IT系统及网络可用性、安全性、稳定性&#xff0c;确保业务连续性的核心工作。通过专业技术手段&#xff0c;对计算机网络、应用系统、电信网络、软硬件环境及运维服务流程等进行综…...

基于Java的不固定长度字符集在指定宽度和自适应模型下图片绘制生成实战

目录 前言 一、需求介绍 1、指定宽度生成 2、指定列自适应生成 二、Java生成实现 1、公共方法 2、指定宽度生成 3、指定列自适应生成 三、总结 前言 在当今数字化与信息化飞速发展的时代&#xff0c;图像的生成与处理技术正日益成为众多领域关注的焦点。从创意设计到数…...

【版本控制】idea中使用git

大家好&#xff0c;我是jstart千语。接下来继续对git的内容进行讲解。也是在开发中最常使用&#xff0c;最重要的部分&#xff0c;在idea中操作git。目录在右侧哦。 如果需要git命令的详解&#xff1a; 【版本控制】git命令使用大全-CSDN博客 一、配置git 要先关闭项目&#xf…...

QT:Qt5 串口模块 (QSerialPort) 在 VS2015 中正确关闭串口避免被占用

以下是使用 Qt5 串口模块 (QSerialPort) 在 VS2015 中正确关闭串口避免被占用的完整示例代码&#xff1a; #include <QSerialPort> #include <QDebug>// 创建全局或类成员变量&#xff08;推荐使用智能指针&#xff09; QSerialPort *serialPort nullptr; // 打开…...

Linux——入门常用基础指令

文章目录 Linux入门常用基础指令使用工具介绍基础指令clear指令pwd指令ls指令cd指令Linux系统下的文件路径及文件存储结构文件结构家目录绝对路径和相对路径tree工具 stat指令which指令alias指令touch指令mkdir指令cat指令rm指令man指令cp指令通配符 * Linux入门常用基础指令 …...

【技术追踪】Differential Transformer(ICLR-2025)

Differential Transformer&#xff1a;大语言模型新架构&#xff0c; 提出了 differential attention mechanism&#xff0c;Transformer 又多了一个小 trick~ 论文&#xff1a;Differential Transformer 代码&#xff1a;https://github.com/microsoft/unilm/tree/master/Diff…...

overlay 模块加载失败问题分析

问题背景 CentOS 7系统上&#xff0c;内核版本是3.10.0-693.21.1.el7.x86_64&#xff0c;加载overlay模块的时候失败了。错误提示说找不到支持的overlay文件系统&#xff0c;让我确认内核足够新并且已经加载了overlay支持。但是检查发现/lib/modules/3.10.0-693.el7.x86_64/ke…...

【Linux网络】应用层自定义协议与序列化

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/qinjh_/category_12891150.html 目录 应用层 再谈 "协议" 网络版计算器 序列化 和 反序列化 重新理解…...

Vue接口平台学习十——接口用例页面2

效果图及简单说明 左边选择用例&#xff0c;右侧就显示该用例的详细信息。 使用el-collapse折叠组件&#xff0c;将请求到的用例详情数据展示到页面中。 所有数据内容&#xff0c;绑定到caseData中 // 页面绑定的用例编辑数据 const caseData reactive({title: "",…...

目标检测中的损失函数(二) | BIoU RIoU α-IoU

BIoU来自发表在2018年CVPR上的文章&#xff1a;《Improving Object Localization With Fitness NMS and Bounded IoU Loss》 论文针对现有目标检测方法只关注“足够好”的定位&#xff0c;而非“最优”的框&#xff0c;提出了一种考虑定位质量的NMS策略和BIoU loss。 这里不赘…...

SpringAI系列 - MCP篇(一) - 什么是MCP

目录 一、引言二、MCP核心架构三、MCP传输层(stdio / sse)四、MCP能力协商机制(Capability Negotiation)五、MCP Client相关能力(Roots / Sampling)六、MCP Server相关能力(Prompts / Resources / Tools)一、引言 之前我们在接入大模型时,不同的大模型通常都有自己的…...

Linux 入门十一:Linux 网络编程

一、概述 1. 网络编程基础 网络编程是通过网络应用编程接口&#xff08;API&#xff09;编写程序&#xff0c;实现不同主机上进程间的信息交互。它解决的核心问题是&#xff1a;如何让不同主机上的程序进行通信。 2. 网络模型&#xff1a;从 OSI 到 TCP/IP OSI 七层模型&…...

沐渥氮气柜控制板温湿度氧含量氮气流量四显智控系统

氮气柜控制板通常用于实时监控和调节柜内环境参数&#xff0c;确保存储物品如电子元件、精密仪器、化学品等&#xff0c;处于低氧、干燥的稳定状态。以下是沐渥氮气柜控制板核心参数的详细介绍及控制逻辑&#xff1a; 一、控制板核心参数显示模块 1&#xff09;‌温度显示‌&am…...

vue3 主题模式 结合 element-plus的主题

vue3 主题模式 结合 element-plus的主题 npm i element-plus --save-dev在 Vue 3 中&#xff0c;实现主题模式主要有以下几种方式 1.使用 CSS 变量&#xff08;自定义属性&#xff09; CSS 变量是一种在 CSS 中定义可重用值的方式。在主题模式中&#xff0c;可以将颜色、字体…...

Redis 有序集合(Sorted Set)

Redis 有序集合&#xff08;Sorted Set&#xff09; 以下从基础命令、内部编码和使用场景三个维度对 Redis 有序集合进行详细解析&#xff1a; 一、基础命令 命令时间复杂度命令含义zadd key score member [score member …] O ( k l o g ( n ) ) O(klog(n)) O(klog(n))&…...

[c语言日寄]免费文档生成器——Doxygen在c语言程序中的使用

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…...

QtCreator的设计器、预览功能能看到程序图标,编译运行后图标消失

重新更换虚拟机&#xff08;Vmware Kylin&#xff09;&#xff0c;重新编译和配置了很多第三方库后&#xff0c;将代码跑到新的这个虚拟机环境中&#xff0c;但是出现程序图标不可见&#xff0c;占位也消失&#xff0c;后来继续检查ui文件&#xff0c;ui文件图标也异常&#x…...

QT文件和文件夹拷贝操作

1.拷贝文件夹 //(源文件目录路劲&#xff0c;目的文件目录&#xff0c;文件存在是否覆盖) bool copyDirectory(const QString& srcPath, const QString& dstPath, bool coverFileIfExist) { QDir srcDir(srcPath); QDir dstDir(dstPath); if (!dstDir.exi…...

面试常用基础算法

目录 快速排序归并排序堆排序 n n n皇后问题最大和子数组爬楼梯中心扩展法求最长回文子序列分割回文串动态规划求最长回文子序列最长回文子串单调栈双指针算法修改 分割回文串滑动窗口栈 快速排序 #include <iostream> #include <algorithm>using namespace std;…...

Python-24:小R的随机播放顺序

问题描述 小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌&#xff0c;播放后将其从歌单中移除。如果歌单中还有歌曲&#xff0c;则会将当前第一首歌移到最后一首。这个过程会一直重复&#xff0c;直到歌单中没有任何歌曲。 例如&#xff0c;给定歌单 [5, 3, 2, 1,…...

悬空引用和之道、之禅-《分析模式》漫谈57

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 “Analysis Patterns”的第5章“对象引用”原文&#xff1a; Unless you can catch all such references, there is the risk of a dangling reference, which often has painful con…...

Python accumulate 函数详解

https://docs.python.org/zh-cn/3/library/itertools.html#itertools.accumulate 在 Python 中&#xff0c;accumulate 是一个生成器&#xff08;generator&#xff09;, 是来自 itertools 模块的一个函数。 它的作用是返回一个迭代器&#xff0c;该迭代器生成输入数据的累积结…...

Cursor可视化大屏搭建__0420

主题:用Cursor怎么进行数据洞察,做AI预测化内容。 Python基础语法与AI python生态强大,代码简洁,相对其他语言Python更好上手,浙江高考将Python列为可选科目 科学计算:Sklearn,Numpy,Pandas 人工智能:Tensorflow,Pytorch 网络爬虫:Scrapy…...

【初阶数据结构】树——二叉树(上)

文章目录 目录 前言 一、树 1.树的概念与结构 2.树相关术语 3.树的表示 二、二叉树 1.概念与结构 2.特殊的二叉树 3.二叉树存储结构 总结 前言 本篇带大家学习一种非线性数据结构——树&#xff0c;简单认识树和二叉数以及了解二叉树的存储结构。 一、树 1.树的概念与结构 树…...

ECharts散点图-散点图14,附视频讲解与代码下载

引言&#xff1a; ECharts散点图是一种常见的数据可视化图表类型&#xff0c;它通过在二维坐标系或其它坐标系中绘制散乱的点来展示数据之间的关系。本文将详细介绍如何使用ECharts库实现一个散点图&#xff0c;包括图表效果预览、视频讲解及代码下载&#xff0c;让你轻松掌握…...

C++中的算术转换、其他隐式类型转换和显示转换详解

C中的类型转换&#xff08;Type Conversion&#xff09;是指将一个数据类型的值转换为另一个数据类型的过程&#xff0c;主要包括&#xff1a; 一、算术类型转换&#xff08;Arithmetic Conversions&#xff09; 算术类型转换通常发生在算术运算或比较中&#xff0c;称为**“标…...