手写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://www.rhkb.cn/news/386094.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十三章 输入子系统实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

IP 泄露: 原因与避免方法

始终关注您的IP信息&#xff01; 您的IP地址不仅显示您的位置&#xff0c;它包含几乎所有的互联网活动信息&#xff01; 如果出现IP泄漏&#xff0c;几乎所有的信息都会被捕获甚至非法利用&#xff01; 那么&#xff0c;网站究竟如何追踪您的IP地址&#xff1f;您又如何有效…

Catalyst优化器:让你的Spark SQL查询提速10倍

目录 1 逻辑优化阶段 2.1 逻辑计划解析 2.2 逻辑计划优化 2.2.1 Catalys的优化过程 2.2.2 Cache Manager优化 2 物理优化阶段 2.1 优化 Spark Plan 2.1.1 Catalyst 的 Join 策略 2.1.2 如何决定选择哪一种 Join 策略 2.2 Physical Plan 2.2.1 EnsureRequirements 规则 3 相关文…

【Unity2D 2022:Data】读取csv格式文件的数据

一、创建csv文件 1. 打开Excel&#xff0c;创建xlsx格式文件 2. 编辑卡牌数据&#xff1a;这里共写了两类卡牌&#xff0c;第一类是灵物卡&#xff0c;具有编号、卡名、生命、攻击四个属性&#xff1b;第二类是法术卡&#xff0c;具有编号、卡名、效果三个属性。每类卡的第一…

qt 如何制作动态库插件

首先 首先第一点要确定我们的接口是固定的&#xff0c;也就是要确定 #ifndef RTSPPLUGIN_H #define RTSPPLUGIN_H #include "rtspplugin_global.h" typedef void (*func_callback)(uint8_t* data,int len,uint32_t ssrc,uint32_t ts,const char* ipfrom,uint16_t f…

【Maven学习】-3.进阶

文章目录 3. 进阶3.1 maven依赖传递特性 3.2 依赖冲突3.2.1 自动选择原则3.2.2 手动排除 3.3 聚合工程3.3.1 继承介绍继承作用继承语法父工程依赖统一管理-dependencyManagement 3.3.2 工程聚合关系简介聚合作用聚合作用 3.4 私服3.4.1 简介3.4.2 Nexus下载安装Nexus3Nexus2 3.…

带你学会Git必会操作

文章目录 带你学会Git必会操作1Git的安装2.Git基本操作2.1本地仓库的创建2.2配置本地仓库 3.认识一些Git的基本概念3.1操作流程&#xff1a; 4.一些使用场景4.1添加文件场景一4.2查看git文件4.3修改文件4.4Git版本回退4.5git撤销修改 5.分支管理5.1查看分支5.2创建本地分支5.3切…

IOS-05 Swift循环控制语句

在 Swift 编程语言中&#xff0c;控制语句用于决定程序的执行流程&#xff0c;使我们能够根据不同的条件和情况来控制代码的执行顺序。下面我们将详细介绍几种常见的控制语句 一、for 循环 let names ["zhangsan","lisi"] for name in names{print(name…

set,map(java)

前言&#xff1a;要了解set和map&#xff0c;首先需要对搜索树和哈希有一定的了解&#xff0c;才能进一步深入的了解set和map。 1.搜索树 &#xff08;1&#xff09;性质&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点值都小于根节点的值。 若它的右子树不…

TypeScript学习篇-类型介绍使用、ts相关面试题

文章目录 基础知识基础类型: number, string, boolean, object, array, undefined, void(代表该函数没有返回值)unknownenum(枚举): 定义一个可枚举的对象联合类型: | (联合类型一次只能一种类型&#xff1b;而交叉类型每次都是多个类型的合并类型。)交叉类型: & (联合类型…

按图搜索新体验:阿里巴巴拍立淘API返回值详解

阿里巴巴拍立淘API是一项基于图片搜索的商品搜索服务&#xff0c;它允许用户通过上传商品图片&#xff0c;系统自动识别图片中的商品信息&#xff0c;并返回与之相关的搜索结果。以下是对阿里巴巴拍立淘API返回值的详细解析&#xff1a; 一、主要返回值内容 商品信息 商品列表…

【算法/学习】前缀和差分

前缀和&&差分目录 1. 前缀和的概念及作用 &#x1f308;概念 &#x1f308;用途 &#x1f319;一维前缀和 &#x1f319;二维前缀和 2. 差分的概念及用途 &#x1f308;概念&#xff1a; &#x1f308;用途 &#x1f319;一维差分 &#x1f319;二维差分 1. …

Linux系统编程——线程池

目录 一&#xff0c;池化技术 二&#xff0c;线程池概念 三&#xff0c;线程池实现 3.1 线程封装 3.2 预备头文件实现 3.3 线程池类的简单实现 3.4 主函数实现 3.5 效果展示 一&#xff0c;池化技术 池化技术是计算机编程领域非常常用的一种技术&#xff0c;该技术可以…

【前端/js】使用js读取本地文件(xml、二进制)内容

目录 说在前面FileReaderDOMParser文本文件二进制文件 说在前面 浏览器版本&#xff1a;Microsoft Edge 126.0.2 (正式版本) (64 位) FileReader MDNFileReader 接口允许 Web 应用程序异步读取存储在用户计算机上的文件&#xff08;或原始数据缓冲区&#xff09;的内容&#x…

CL4056D 1A锂离子电池线性充电器芯片IC

一般描述 CL4056D是一款ESOP8封装的独立线性锂离子电池充电器。由于外部元件较少&#xff0c;因此CL4056D非常适合用于各种便携式应用。充电电流可以通过外部电阻器进行编程。在待机模式下&#xff0c;供电电流将降低到约35uA。当输入电压断开时&#xff0c;CL4056 D将进…

UWA Gears正式上线,助力移动平台性能优化

亲爱的开发者朋友们&#xff0c; 我们非常激动地向大家宣布&#xff0c;UWA最新的无SDK性能分析工具 - UWA Gears&#xff0c;现已正式发布&#xff01;无论您使用的是哪种开发引擎&#xff0c;这款工具都能轻松应对&#xff0c;为您的项目保驾护航。更令人心动的是&#xff0c…

Lua编程

文章目录 概述lua数据类型元表注意 闭包表现 实现 lua/c 接口编程skynet中调用层次虚拟栈C闭包注册表userdatalightuserdata 小结 概述 这次是skynet&#xff0c;需要一些lua/c相关的。写一篇博客&#xff0c;记录下。希望有所收获。 lua数据类型 boolean , number , string…

在react中如何计算本地存储体积

1.定义useLocalStorageSize钩子函数 // 计算localStorage大小 function useLocalStorageSize() {const [size, setSize] useState(0);useEffect(() > {const calculateSize () > {let totalSize 0;for (let key in localStorage) {//过滤掉继承自原型链的属性if (loc…

Redis是多线程还是单线程?

文章目录 1、用户态和内核态2、阻塞IO3、非阻塞IO4、IO多路复用4.1 select4.2 poll4.3 epoll4.4 epoll中的ET和LT4.5 epoll的服务端流程 5、信号驱动6、异步IO7、对比8、Redis是单线程的吗&#xff1f;9、单线程多线程网络模型变更 1、用户态和内核态 1、ubuntu和Centos 都是Li…

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

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