手写spring简易版本,让你更好理解spring源码

首先我们要模拟spring,先搞配置文件,并配置bean

创建我们需要的类,beandefito,这个类是用来装解析后的bean,主要三个字段,id,class,scop,对应xml配置的属性

package org.zhw.ezspring.domain;
//解析后的bean
public class BeanDefinition {private String id;private String className;private String scope;public BeanDefinition(String id, String className, String scope) {this.id = id;this.className = className;this.scope = scope;}public BeanDefinition() {}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}
}

然后配置下我们要用的beandemo,这个后面我没用,但是懂的都懂,让大家更好理解下,xml中class,就是我们bean的路径,因为我们要用到反射。

package org.zhw.ezspring.domain;public class DemoBean {private String Name;private String age;public String getName() {return Name;}public void setName(String name) {Name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}public DemoBean() {}public DemoBean(String name, String age) {Name = name;this.age = age;}
}

对了,我们还要使用一个jar包,这个可以用来解析xml文件,非常好用

然后我们开始模拟手写简易版spring,由于我已经全部写完了,就先把核心代码写在下面。

以防大家看不清,我把文件目录展示下

package org.zhw.ezspring.factory;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.zhw.ezspring.domain.BeanDefinition;
import org.zhw.ezspring.domain.DemoBean;import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;public class BeanFactory {
//    用来装beandefiton 的map
static ConcurrentHashMap<String, BeanDefinition> beanDiMap = new ConcurrentHashMap<>();
//    用来装单例bean的map
static HashMap<String, DemoBean> objectObjectHashMap = new HashMap<>();
//     实例化的时候,就加载beanpublic  BeanFactory(){
//        解析xml配置文件this("E:\\ideaspace\\ez-spring\\src\\resouces\\application.xml");}public BeanFactory(String path) {SAXReader reader = new SAXReader();try {// 读取XML文件Document document = reader.read(new File(path));// 获取根元素Element rootElement = document.getRootElement();// 遍历元素List<Element> elements = rootElement.elements();for (Element element : elements) {BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setClassName(element.attributeValue("className"));beanDefinition.setId(element.attributeValue("id"));beanDefinition.setScope(element.attributeValue("scope"));String scope = element.attributeValue("scope");
//                默认为单例if(scope!=null&&!"".equals(scope)){beanDefinition.setScope("singleton");}System.out.println(beanDefinition);
//                放入beandefitionmapbeanDiMap.put(beanDefinition.getId(),beanDefinition);iniSingletonObjects();}} catch (DocumentException e) {e.printStackTrace();}}private void iniSingletonObjects() {
//        1.遍历map
//        2.判断是不是单例,是就放入它Iterator<Map.Entry<String, BeanDefinition>> iterator = beanDiMap.entrySet().iterator();while (iterator.hasNext()){Map.Entry<String, BeanDefinition> entry = iterator.next();BeanDefinition value = entry.getValue();String scope = value.getScope();String id = value.getId();if (scope.equals("singleton")){DemoBean demoBean = new DemoBean();demoBean.setName("z");objectObjectHashMap.put(id,demoBean);}}}public   Object getBean(String id ) throws DocumentException {
//根据id,作为key去beandifitionmap中遍历,判断是单例还是多例,是单例就去单例map中找,不是则直接反射。
//        BeanFactory beanFactory = new BeanFactory();BeanDefinition beanDefinition = beanDiMap.get(id);if (Objects.isNull(beanDefinition)){throw new RuntimeException("beanFactory is null");}if ("singleton".equals(beanDefinition.getScope())){BeanDefinition beanDefinition1 = beanDiMap.get(id);return beanDefinition1;}
//        如何是多例,则使用反射创建beantry {Class<?> aClass = Class.forName(beanDefinition.getClassName());DemoBean o = (DemoBean) aClass.newInstance();} catch (Exception e) {throw new RuntimeException("获取bean失败");}return null;}
// 通过class,来获取beanpublic  <T>T getBean(Class<T> classz){String name = classz.getName();Set<Map.Entry<String, BeanDefinition>> entries = beanDiMap.entrySet();Map.Entry<String, BeanDefinition> first = entries.stream().filter(x ->name.equals(x.getValue().getClassName())).findFirst().get();BeanDefinition value = first.getValue();if (value.getScope().equals("singleton")){return (T) beanDiMap.get(value.getId());}
//        不是单例就通过反射创建新的else {try {String id = value.getId();BeanDefinition beanDefinition = beanDiMap.get(id);Class<?> aClass = Class.forName(beanDefinition.getClassName());DemoBean o = (DemoBean) aClass.newInstance();} catch (Exception e) {throw new RuntimeException("获取bean失败");}}return null;}public static void main(String[] args) {BeanFactory beanFactory = new BeanFactory();try {Object demo1 = beanFactory.getBean("demo1");Object demo2 = beanFactory.getBean("demo1");System.out.println(demo1==demo2);} catch (Exception e) {throw new RuntimeException(e);}}}

这是我们的结果,免得说我失败了,两个单例bean的地址完全相同

ok,让我们开始解析我手写的代码,非常简单易懂,哈哈

首先我们需要new,两个map,一个用来装解析bean后的beandefitonmap,一个用来装单例bean,因为spring原理,bean单例,就是要从单例map里面找得嘛。

然后我们首先要解析xml,new个工厂,在new工厂的过程中,我们就要对bean进行解析,包装为beandefiton,放到beandefitonmap中去。同时要默认为单例bean,所以没有加scope的bean要写为单例bean。还要对beandefinitionmap进行遍历,把单例bean,放入单例beanmap中

为什么我们可以遍历xml,是因为我们用了dom4j,百度ai直接搜,dom4j解析xml,我直接粘贴复制过来的

一个有参,一个无参,这个应该看得懂撒。

       private void iniSingletonObjects() {
//        1.遍历map
//        2.判断是不是单例,是就放入它Iterator<Map.Entry<String, BeanDefinition>> iterator = beanDiMap.entrySet().iterator();while (iterator.hasNext()){Map.Entry<String, BeanDefinition> entry = iterator.next();BeanDefinition value = entry.getValue();String scope = value.getScope();String id = value.getId();if (scope.equals("singleton")){DemoBean demoBean = new DemoBean();demoBean.setName("z");objectObjectHashMap.put(id,demoBean);}}}
public  BeanFactory(){
//        解析xml配置文件this("E:\\ideaspace\\ez-spring\\src\\resouces\\application.xml");}public BeanFactory(String path) {SAXReader reader = new SAXReader();try {// 读取XML文件Document document = reader.read(new File(path));// 获取根元素Element rootElement = document.getRootElement();// 遍历元素List<Element> elements = rootElement.elements();for (Element element : elements) {BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setClassName(element.attributeValue("className"));beanDefinition.setId(element.attributeValue("id"));beanDefinition.setScope(element.attributeValue("scope"));String scope = element.attributeValue("scope");
//                默认为单例if(scope!=null&&!"".equals(scope)){beanDefinition.setScope("singleton");}System.out.println(beanDefinition);
//                放入beandefitionmapbeanDiMap.put(beanDefinition.getId(),beanDefinition);iniSingletonObjects();}} catch (DocumentException e) {e.printStackTrace();}}

然后我们就来写关于获取bean的方式,一个根据id获取,一个根据class获取。

根据id,先去beandefitonmap中去找,根据id,然后判断是不是空,还是单例bean,单例bean就去单例map中去找,多例则是用反射创建bean。

    public   Object getBean(String id ) throws DocumentException {
//根据id,作为key去beandifitionmap中遍历,判断是单例还是多例,是单例就去单例map中找,不是则直接反射。
//        BeanFactory beanFactory = new BeanFactory();BeanDefinition beanDefinition = beanDiMap.get(id);if (Objects.isNull(beanDefinition)){throw new RuntimeException("beanFactory is null");}if ("singleton".equals(beanDefinition.getScope())){BeanDefinition beanDefinition1 = beanDiMap.get(id);return beanDefinition1;}
//        如何是多例,则使用反射创建beantry {Class<?> aClass = Class.forName(beanDefinition.getClassName());DemoBean o = (DemoBean) aClass.newInstance();} catch (Exception e) {throw new RuntimeException("获取bean失败");}return null;}

根据class获取bean,先用class获取bean的名字,然后我们去beandefitonmap中去找bean,然后判断是不是单例bean,这里我脑子有点混乱了,从beandftionmap中已经获取了bean,然后还要去单例map中获取,这不是多此一举吗?如果不是,自己通过反射,new一个新的bean

关于我通过class,获取bean,我感觉我写的很混乱,写的不是很好,如果错了,不要怪我哈,以供借鉴提醒。

public  <T>T getBean(Class<T> classz){String name = classz.getName();Set<Map.Entry<String, BeanDefinition>> entries = beanDiMap.entrySet();Map.Entry<String, BeanDefinition> first = entries.stream().filter(x ->name.equals(x.getValue().getClassName())).findFirst().get();BeanDefinition value = first.getValue();if (value.getScope().equals("singleton")){return (T) beanDiMap.get(value.getId());}
//        不是单例就通过反射创建新的else {try {String id = value.getId();BeanDefinition beanDefinition = beanDiMap.get(id);Class<?> aClass = Class.forName(beanDefinition.getClassName());DemoBean o = (DemoBean) aClass.newInstance();} catch (Exception e) {throw new RuntimeException("获取bean失败");}}return null;}

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

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

相关文章

安科瑞邀您走进2024北京电气设计第44届年会

2024年7月11日&#xff0c;2024建筑电气高峰论坛暨北京电气设计第44届年会在京如期而至&#xff0c;各路精英齐聚一堂&#xff0c;围绕智慧建筑、数据中心、工业厂房配电、储能技术等热点问题展开讨论。安科瑞携企业微电网智慧能源的一站式服务解决方案亮相盛会&#xff0c;尽享…

ssh出现Permission denied(publickey,gssapi-keyex,gssapi-with-mic).

目录 1.报错如下 ​编辑2.编辑sshd配置文件 ​编辑3.解决报错 &#x1f310; 无论你是初学者还是经验丰富的专家&#xff0c;都能在这里找到志同道合的朋友&#xff0c;一起进步&#xff0c;共同探索运维领域的各种挑战和机遇。 1.报错如下 2.编辑sshd配置文件 vim /etc/ss…

【安全规范】软件开发安全设计指南(Word文档)

2.1.应用系统架构安全设计要求 2.2.应用系统软件功能安全设计要求 2.3.应用系统存储安全设计要求 2.4.应用系统通讯安全设计要求 2.5.应用系统数据库安全设计要求 2.6.应用系统数据安全设计要求 软件全套精华资料包清单部分文件列表&#xff1a; 工作安排任务书&#xff0c;可行…

PEFT LoRA 介绍(LoRA微调使用的参数及方法)

一 PEFT LoRA 介绍 官网简介如下图&#xff1a; 翻译过来是&#xff1a;低秩自适应(LoRA)是一种PEFT方法&#xff0c;它将一个大矩阵在注意层分解成两个较小的低秩矩阵。这大大减少了需要微调的参数数量。 说的只是针对注意力层&#xff0c;其实我自己平时微调操作注意力层多…

vue3前端开发-小兔鲜项目-登录和非登录状态下的模板适配

vue3前端开发-小兔鲜项目-登录和非登录状态下的模板适配&#xff01;有了上次的内容铺垫&#xff0c;我们可以根据用户的token来判定&#xff0c;到底是显示什么内容了。 1&#xff1a;我们在对应的导航组件内修改完善一下内容即可。 <script setup> import { useUserSt…

Mysql或MariaDB数据库的用户与授权操作——实操保姆级教程

一、问题描述 在日常的工作中,我们需要给不同角色的人员创建不同的账号,他们各自可访问的数据库或权限不一样,这时就需要创建用户和赋予不同的权限内容了。 二、问题分析 1、创建不同的角色账号; 2、给这些账号授予各自可访问数据库的权限。 三、实现方法 Centos8安装…

CHIP第三章作业

一&#xff0c;实验拓扑 二&#xff0c;实验要求 1、R5为ISP&#xff0c;只能进行Ip地址配置&#xff0c;其所有地址均配为公有IP地址; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方; R2与R5之间使用ppp的cHAP认证&#xff0c;R5为主认证方; R3与R5之间使用HDLC封装; …

数据结构--单链表代码(王道书上代码手敲!!!)c++

目录 1.带头结点的初始化以及检查单链表是否为空 2.不带头结点的单链表初始化以及表是否为空检查 3.带头结点按位序插入 4.不带头结点的按位序插入 5.带头结点的后插&#xff0c;前插&#xff0c;按位删除&#xff0c;删除固定节点操作 6 不带头结点的后插&#xff0c;前…

SLAM:BALM: 激光雷达映射的捆绑调整【方法解析-1】

目录 摘要I. 引言II. 相关工作III. BA公式及其导数A. 直接BA公式摘要 在视觉SLAM中,滑动窗口关键帧上的局部束调整(BA)已被广泛使用,并被证明在降低漂移方面非常有效。但在激光雷达SLAM中,很少使用BA方法,因为稀疏特征点(如边缘和平面)使得精确的点匹配变得不可能。在…

如何在 SpringBoot 中优雅的做参数校验?

一、故事背景 关于参数合法性验证的重要性就不多说了&#xff0c;即使前端对参数做了基本验证&#xff0c;后端依然也需要进行验证&#xff0c;以防不合规的数据直接进入服务器&#xff0c;如果不对其进行拦截&#xff0c;严重的甚至会造成系统直接崩溃&#xff01; 本文结合…

【Qt】QWidget核心属性相关API

目录 一. enabled——是否可用 二. geometry——几何位置 window frame 三. windowTitle——窗口标题 四. windowIcon——窗口图标 ​qrc文件 五. windowOpacity——透明度 六. cursor——光标 自定义光标 七. font——字体 八. toolTip——提示栏 九. focusPolic…

Web开发:ASP.NET CORE中前端使用Ajax定时获取后端数据

一、低难度&#xff08;刷新a标签&#xff09; 1、需求 给a标签每15s刷新一次&#xff0c;显示最新的时间&#xff08;时间必须由后端获取&#xff09; 应该如何操作呢 2、代码 后端 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Mi…

液态神经网络到底是什么?

液体神经网络是一种应用范围极其广泛的机器学习工具&#xff0c;不仅可以像传统神经网络那样学习并执行图像识别、自然语言处理和语音合成等多种任务&#xff1b;还突破了传统神经网络难以适应随时间变化的新数据的限制&#xff0c;能够应用于医学诊断和自动驾驶等涉及动态和不…

【Plotly-驯化】一文教你通过plotly画出动态可视化多变量分析:create_scatterplotmatrix

【Plotly-驯化】一文教你通过plotly画出动态可视化多变量分析&#xff1a;create_scatterplotmatrix 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &am…

无法解析插件 org.apache.maven.plugins:maven-war-plugin:3.2.3(已解决)

文章目录 1、问题出现的背景2、解决方法 1、问题出现的背景 最开始我想把springboot项目转为javaweb项目&#xff0c;然后我点击下面这个插件 就转为javaweb项目了&#xff0c;但是我后悔了&#xff0c;想要还原成springboot项目&#xff0c;点开项目结构关于web的都移除了&am…

MySql 触发器、存储器练习

一&#xff1a; 触发器 1、建立两个表:goods(商品表)、orders(订单表) 查看数据库&#xff1a;mysql> show databases; 使用数据库&#xff1a;mysql> use mydb16_trigger; 创建goods表&#xff1a; mysql> create table goods(gid char(8) not null primary key, …

海外发稿:打造希腊媒体宣发新局面

随着全球经济一体化的不断深入&#xff0c;企业对于海外市场的拓展需求日益迫切。在这个过程中&#xff0c;媒体宣发作为一种有效的市场推广手段&#xff0c;已经成为企业出海的重要策略之一。希腊&#xff0c;作为欧洲的重要经济体&#xff0c;拥有丰富的文化底蕴和众多的历史…

自动IP地址vs固定IP地址:哪个更快?深度解析与比较

在数字化时代&#xff0c;网络连接已成为我们日常生活和工作中不可或缺的一部分。而在网络配置中&#xff0c;IP地址的选择——无论是自动获取还是固定设置&#xff0c;都是影响网络性能和管理的关键因素之一。许多人常常疑惑&#xff1a;自动IP地址和固定IP地址哪个快一点&…

Linux中如何用ida调试fork后的子进程

原文链接 > https://redqx.github.io/linux/2024/07/24/linux-debugfork.html 本文的一些图片引用可能有一些问题, 比如数据不对劲,但无伤大雅 自己懒得粘贴图片了 环境: wsl-kali-2024 ida-7.7 插件: Lazy_ida, 还有一个什么插件不知道什么名字, 可以把汇编转字节码 …

基于PaddleClas的人物年龄分类项目

目录 一、任务概述 二、算法研发 2.1 下载数据集 2.2 数据集预处理 2.3 安装PaddleClas套件 2.4 算法训练 2.5 静态图导出 2.6 静态图推理 三、小结 一、任务概述 最近遇到个需求&#xff0c;需要将图像中的人物区分为成人和小孩&#xff0c;这是一个典型的二分类问题…