手动开发-简单的Spring基于XML配置的程序--源码解析

简介: 手动开发-简单的Spring基于XML配置的程序--源码解析

本文带着大家写一个简单的Spring容器,通过读取beans.xml配置文件,获取第一个JavaBean:Monster的对象,并给对象赋值,放入到容器中,输出对象信息。

先回顾一下使用Spring时,我们是通过ClassPathXmlApplicationContext得到ioc容器,容器自动读取beans.xml配置文件,我们通过容器的getBean方法获取到对象,并输出该对象。

现在要做的就是:

  • 自己实现一个ioc容器,前提是自己实现一个属于自己的ClassPathXmlApplicationContext()
  • ClassPathXmlApplicationContext()中要提供一个getBean()方法。

思路分析@

这里其实重点分析ClassPathXmlApplicationContext()的具体实现过程:

  • 定义一个iocConcurrentHashMap,存放对象名id和对象的映射。
  • 创建一个构造器,将下面的操作都放在这个构造器里
  • 使用xml解析技术-dom4j技术,将beans.xml文件中的信息读取出来,并获取到节点信息的属性值
  • 使用反射创建对象
  • 将对象放入到ioc
  • 提供一个getBean方法

在通过 xml解析技术-dom4j技术,将beans.xml文件中的信息读取出来,并获取到节点信息的属性值时,需要先获取到beans.xml文件所在路径 。这里的路径是指 项目 编译后的文件所在路径,也就是target工作目录下的路径,我们的beans.xml文件是放在resource目录下的,经过编译后就会跑到target/classes目录下,所以在这里我们通过dom4j读取的目录应该是D:/Java/JavaProjects/spring-context-v1/target/classes/ ;完整的 文件工作路径应该是D:/Java/JavaProjects/spring-context-v1/target/classes/beans.xml ;

String path = this.getClass().getResource("/").getPath();
//        System.out.println("path="+path);
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File(path + iocBeanXmlFile));

在获取到document文档对象以后,我们就拿到了beans.xml里的所有内容,这个时候,我们获取到根节点,再通过根节点获取到bean标签的第一个bean对象,bean标签内的属性极其属性值都能获取到。通过bean标签的class属性可以获取到全类路径,拿到类路径就可以通过反射创建对象,这个对象的类型就是你类路径的对象。

SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(new File(path + iocBeanXmlFile));
        Element rootElement = document.getRootElement();
        Element bean = (Element) rootElement.elements("bean").get(0);
        String id = bean.attributeValue("id");
        String classFullPath = bean.attributeValue("class");
        System.out.println("id="+id);
        System.out.println("classFullPath="+classFullPath);
        List<Element> property = bean.elements("property");
        String monsterId = property.get(0).attributeValue("value");
        String name = property.get(1).attributeValue("value");
        System.out.println("monsterId="+monsterId);
        System.out.println("name="+name);

通过反射创建的对象才能和Monster对象有相似的结构,我们可以把beans.xml中取出来的bean对象的属性值注入到我们反射创建的对象中,再把这个对象加入到ioc集合中。

Class<?> aClass = Class.forName(classFullPath);
        Monster o = (Monster) aClass.newInstance();
        o.setId(Integer.valueOf(monsterId));
        o.setName(name);
        ioc.put(id,o);

最后提供一个getBean方法,给出 monsterId的时候,能从ioc容器中找到对应映射的Monster对象。

public Object getBean(String id){
        return ioc.get(id);
    }

最后就实现了上图,我们只需要在xml文件中配置bean对象,再把xml文件的名字交给LingHuApplication容器进行初始化就可以得到一个ioc容器,ioc容器的本质就是一个ConcurrentHashMap。内部是通过dom4j去读取了bean对象的配置信息,通过这些信息如classFullPath反射创建对象,在往这个新对象中注入读取到bean对象的配置信息。这个新对象被我们放入到ConcurrentHashMap中了,我们通过getBean(String monsterId)方法去遍历ConcurrentHashMap找到新对象。

做这些事情的意义就在于,我们将配置工作和业务工作进行了分离,繁琐的对象管理工作一律通过配置文件来完成,降低了代码的耦合性,剥离了业务代码。所以Spring的容器思想的本质就是:ConcurrentHashMap+反射创建对象。

完整代码&:

LingHuApplication.java:

package com.linghu.spring.linghuapplication;
import com.linghu.spring.bean.Monster;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.context.annotation.ComponentScan;
import java.io.File;
import java.net.MalformedURLException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @author 
 * @version 1.0
 *  * 1. 这个程序用于实现Spring的一个简单容器机制
 *  * 2. 后面我们还会详细的实现
 *  * 3. 这里我们实现如何将beans.xml文件进行解析,并生成对象,放入容器中
 *  * 4. 提供一个方法 getBean(id) 返回对应的对象
 *  * 5. 这里就是一个开胃小点心, 理解Spring容器的机制
 */
public class LingHuApplication {
    private ConcurrentHashMap<String, Object> ioc =
            new ConcurrentHashMap<>();
    public LingHuApplication(String iocBeanXmlFile) throws MalformedURLException, DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        String path = this.getClass().getResource("/").getPath();
//        System.out.println("path="+path);
        //得到一个解析器
        SAXReader saxReader = new SAXReader();
        //老师的代码技巧->debug 看看document对象的属性
        //分析了document对象的底层结构
        Document document = saxReader.read(new File(path+iocBeanXmlFile));
        //1. 得到rootElement, 你是OOP
        Element rootElement = document.getRootElement();
        //2. 得到第一个bean-monster01
        Element bean = (Element) rootElement.elements("bean").get(0);
        //获取到第一个bean-monster01的相关属性
        String id = bean.attributeValue("id");
        String classFullPath = bean.attributeValue("class");
        List<Element> property = bean.elements("property");
        System.out.println("id="+id);
        System.out.println("classFullPath="+classFullPath);
        //获取bean对象中的property属性值-id和name
        String name = property.get(1).attributeValue("value");
        String monsterId = property.get(0).attributeValue("value");
        System.out.println("name="+name);
        System.out.println("id="+monsterId);
        //使用反射创建对象
        Class<?> aClass = Class.forName(classFullPath);
        //o对象就是monster对象
        Monster o = (Monster) aClass.newInstance();
//        System.out.println("o="+o);
        o.setId(Integer.valueOf(monsterId));
        o.setName(name);
        //将创建好的对象放入到ioc对象中
        ioc.put(id,o);
    }
    //提供一个getBean(id)返回对应的bean对象
    public Object getBean(String id){
        return ioc.get(id);
    }
}

Gitee:《手动开发-简单的Spring基于XML配置的程序》

目录
相关文章
|
3月前
|
数据采集 人工智能 Java
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
DevDocs是一款基于智能爬虫技术的开源工具,支持1-5层深度网站结构解析,能将技术文档处理时间从数周缩短至几小时,并提供Markdown/JSON格式输出与AI工具无缝集成。
142 1
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
|
3月前
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
337 2
|
2月前
|
域名解析 应用服务中间件 Shell
使用nps配置内网穿透加域名解析
使用nps配置内网穿透加域名解析
380 76
|
3月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
3月前
|
前端开发 Java UED
从基础到进阶:Spring Boot + Thymeleaf 整合开发中的常见坑与界面优化
本文深入探讨了 **Spring Boot + Thymeleaf** 开发中常见的参数绑定问题与界面优化技巧。从基础的 Spring MVC 请求参数绑定机制出发,分析了 `MissingServletRequestParameterException` 的成因及解决方法,例如确保前后端参数名、类型一致,正确设置请求方式(GET/POST)。同时,通过实际案例展示了如何优化支付页面的视觉效果,借助简单的 CSS 样式提升用户体验。最后,提供了官方文档等学习资源,帮助开发者更高效地掌握相关技能。无论是初学者还是进阶用户,都能从中受益,轻松应对项目开发中的挑战。
114 0
|
19天前
|
Java API 微服务
Java 21 与 Spring Boot 3.2 微服务开发从入门到精通实操指南
《Java 21与Spring Boot 3.2微服务开发实践》摘要: 本文基于Java 21和Spring Boot 3.2最新特性,通过完整代码示例展示了微服务开发全流程。主要内容包括:1) 使用Spring Initializr初始化项目,集成Web、JPA、H2等组件;2) 配置虚拟线程支持高并发;3) 采用记录类优化DTO设计;4) 实现JPA Repository与Stream API数据访问;5) 服务层整合虚拟线程异步处理和结构化并发;6) 构建RESTful API并使用Springdoc生成文档。文中特别演示了虚拟线程配置(@Async)和StructuredTaskSco
70 0
|
2月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
307 8
|
3月前
|
人工智能 Java 定位技术
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
本文详细讲解了Java开发者如何基于Spring AI Alibaba框架玩转MCP(Model Context Protocol),涵盖基础概念、快速体验、服务发布与调用等内容。重点包括将Spring应用发布为MCP Server(支持stdio与SSE模式)、开发MCP Client调用服务,以及在Spring AI Alibaba的OpenManus中使用MCP增强工具能力。通过实际示例,如天气查询与百度地图路线规划,展示了MCP在AI应用中的强大作用。最后总结了MCP对AI开发的意义及其在Spring AI中的实现价值。
1115 9

推荐镜像

更多
  • DNS