Spring如何通过XML注册Bean

news2025/4/22 8:02:42

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

上篇内容: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);  
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

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

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

【版本控制】idea中使用git

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

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…

【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。 这里不赘…

Linux 入门十一:Linux 网络编程

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

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

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

[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…

面试常用基础算法

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

悬空引用和之道、之禅-《分析模式》漫谈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…

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

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

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

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

GAIA-2:用于自动驾驶的可控多视图生成世界模型

25年3月来自英国创业公司 Wayze 的论文“GAIA-2: A Controllable Multi-View Generative World Model for Autonomous Driving”。&#xff08;注&#xff1a;23年9月其发布GAIA-1&#xff09; 生成模型为模拟复杂环境提供一种可扩展且灵活的范例&#xff0c;但目前的方法不足…

浅谈AI致幻

文章目录 当前形势下存在的AI幻觉&#xff08;AI致幻&#xff09;什么是AI幻觉AI幻觉的类型为什么AI会产生幻觉AI幻觉的危害与影响当前应对AI幻觉的技术与方法行业与学术界的最新进展未来挑战与展望结论 当前形势下存在的AI幻觉&#xff08;AI致幻&#xff09; 什么是AI幻觉 …

车载软件架构 --- 二级boot设计说明需求规范

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…

Java高效合并Excel报表实战:GcExcel让数据处理更简单

前言&#xff1a;为什么需要自动化合并Excel&#xff1f; 在日常办公场景中&#xff0c;Excel报表合并是数据分析的基础操作。根据2023年企业办公效率报告显示&#xff1a; 财务人员平均每周花费6.2小时在Excel合并操作上人工合并的错误率高达15%90%的中大型企业已采用自动化…

第十四届蓝桥杯 2023 C/C++组 平方差

目录 题目&#xff1a; 题目描述&#xff1a; 题目链接&#xff1a; 思路&#xff1a; 核心思路&#xff1a; 第一种思路&#xff1a; 第二种思路&#xff1a; 坑点&#xff1a; 代码&#xff1a; 数学找规律 O(n) 50分代码详解&#xff1a; O(1)满分代码详解&#x…