第二步->手撕spring源码之bean操作

本步骤目标
本步骤继续完善 Spring Bean 容器框架的功能开发,在这个开发过程中会用到较多的接口、类、抽象类,它们之间会有类的实现、类的继承。
这一次我们把 Bean 的创建交给容器,而不是我们在调用时候传递一个实例化好的 Bean 对象,另外还需要考虑单例对象,在对象的二次获取时是可以从内存中获取对象的。此外不仅要实现功能还需要完善基础容器框架的类结构体。
设计如下操作

A:这里主要使用魔板方法模式进行设计定义 BeanFactory 这样一个 Bean 工厂,提供 Bean 的获取方法 getBean(String name),之后这个 Bean 工厂接口由抽象类 AbstractBeanFactory 实现
B:那么在继承抽象类 AbstractBeanFactory 后的 AbstractAutowireCapableBeanFactory 就可以实现相应的抽象方法了,因为 AbstractAutowireCapableBeanFactory 本身也是一个抽象类,
C:单例 SingletonBeanRegistry 的接口定义实现,而 DefaultSingletonBeanRegistry 对接口实现后,会被抽象类 AbstractBeanFactory 继承。
spring的bean的全景图
在这里插入图片描述

以下为实战部分

public class BeanDefinition {private Class classBean;public BeanDefinition(Class classBean){this.classBean=classBean;}public Class getClassBean() {return classBean;}public void setClassBean(Class classBean) {this.classBean = classBean;}
}

在 Bean 定义类中已经把上一步骤中的 Object bean 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。

public interface SingletonBeanRegistry {Object getSingleton(String beanName);
}

这里接口之定义一个获取bean的方法。

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {Map<String, Object> singletonObjects = new ConcurrentHashMap<>();@Overridepublic Object getSingleton(String beanName) {return singletonObjects.get(beanName);}protected void addSingleton(String beanName, Object singletonObject) {singletonObjects.put(beanName, singletonObject);}
}

以上的DefaultSingletonBeanRegistry 是默认注册bean的抽象实现,实现了一个受保护的 addSingleton 方法,这个方法可以被继承此类的其他类调用。

public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {@Overridepublic Object getBean(String name) {Object singleton = getSingleton(name);if (singleton != null) {return singleton;}BeanDefinition beanDefinition = getBeanDefinition(name);return createBean(name, beanDefinition);}protected abstract Object createBean(String name, BeanDefinition beanDefinition);protected abstract BeanDefinition getBeanDefinition(String name) throws BeansException;
}

1:AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。
2:BeanFactory 的实现,在方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。
3:后续继承抽象类 AbstractBeanFactory 的类有两个,包括:AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory,这两个类分别做了相应的实现处理。
实例化Bean类(AbstractAutowireCapableBeanFactory)

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {@Overrideprotected Object createBean(String name, BeanDefinition beanDefinition) {Object bean = null;try {bean = beanDefinition.getClassBean().newInstance();} catch (InstantiationException | IllegalAccessException e) {throw new BeansException("Instantiation of bean failed", e);}addSingleton(name, bean);return bean;}
}

核心类实现(DefaultListableBeanFactory)


public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {beanDefinitionMap.put(beanName, beanDefinition);}@Overrideprotected BeanDefinition getBeanDefinition(String name) throws BeansException {BeanDefinition beanDefinition = beanDefinitionMap.get(name);if (beanDefinition == null) throw new BeansException("No bean named '" + name + "' is defined");return beanDefinition;}
}

1:DefaultListableBeanFactory 在 Spring 源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码,与源码类名保持一致。
2:DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactory 和 AbstractBeanFactory 等一连串的功能实现。所以有时候你会看到一些类的强转,调用某些方法,也是因为你强转的类实现接口或继承了某些类。
3:除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,当然你还会看到一个 getBeanDefinition 的实现,这个方法我们文中提到过它是抽象类 AbstractBeanFactory 中定义的抽象方法。现在注册Bean定义与获取Bean定义就可以同时使用了,是不感觉这个套路还蛮深的。接口定义了注册,抽象类定义了获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里
以下进行测试

@Testpublic void Test_BeanFAcotyr() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 2.注册 beanBeanDefinition beanDefinition = new BeanDefinition(UserService.class);beanFactory.registerBeanDefinition("userService", beanDefinition);// 3.第一次获取 beanUserService userService = (UserService) beanFactory.getBean("userService");userService.queryUserInfo();}@Testpublic void Test_BeanFAcotyr_two() {// 1.初始化 BeanFactoryDefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// 2.注册 beanBeanDefinition beanDefinition = new BeanDefinition(UserService.class);beanFactory.registerBeanDefinition("userService", beanDefinition);// 3.第一次获取 beanUserService userService = (UserService) beanFactory.getBean("userService");userService.queryUserInfo();
//// 4.第二次获取 bean from SingletonUserService userService_singleton = (UserService) beanFactory.getBean("userService");userService_singleton.queryUserInfo();}
查询用户信息
查询用户信息Process finished with exit code 0

总结
这里与上一步的操作区别在于 这里把 UserService.class 传递给了 BeanDefinition 而不是像上一章节那样直接 new UserService() 操作。
这里会有两次测试信息,一次是获取 Bean 时直接创建的对象,另外一次是从缓存中获取的实例化对象。
在这里插入图片描述
以上是第二步->手撕spring源码之bean操作 关注老哥带你上高速哦。。。。 后续继续完成手写spring源码。
在这里插入图片描述

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

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

相关文章

数据库分库分表思路

一、分库分表的概念 数据过于庞大操作时获取数据缓慢针对于此状况&#xff0c;把原本存储于一个数据库&#xff08;表&#xff09;的数据 按照一定规律分别存储到多个库&#xff08;表&#xff09;。二、为什么要分库分表 当一个程序或系统的不断完善和运行时所负载的业务随着时…

【git】通过JetBrains IDE对git的操作

应该适用于所有jetbrains产品。 一、拉取(pull)代码 上方工具栏-Git-克隆。然后填写git地址与本地存放地址。 二、搁置 修改代码后搁置代码&#xff08;不提交&#xff0c;但是也不撤销已修改的代码&#xff0c;把它暂存起来&#xff09;。 界面的左上角。1->2->3。…

【网站项目】SpringBoot803房屋租赁管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Rust :源代码的分层模块结构组织

在设计和组织多个业务模块的代码时&#xff0c;你需要考虑业务模块之间的耦合度、代码的可维护性以及未来的扩展性。根据你的项目需求&#xff0c;以下是两种常见的组织方式&#xff1a; 1. 每个业务模块都有自己的接口、控制和模型文件夹 如果各个业务模块之间的耦合度较低&…

14.跳跃游戏Ⅱ

文章目录 题目简介题目解答解法一&#xff1a;贪心算法动态规划代码&#xff1a;复杂度分析&#xff1a; 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 跳跃游戏Ⅱ 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一&#xff1a;贪心算法动态规划…

《QT实用小工具·六十三》QT实现微动背景,界面看似静态实则动态

1、概述 源码放在文章末尾 该项目实现了微动背景&#xff0c;界面看似静态实则动态&#xff0c;风动&#xff0c;幡动&#xff0c;仁者心动&#xff0c;所以到底是什么在动&#xff1f;哈哈~ 界面会偷偷一点一点改动文字颜色的颜色填充。 虽然是动态&#xff0c;但是慢到难以…

Python---Numpy万字总结(2)

NumPy的应用&#xff08;2&#xff09; 数组对象的方法 获取描述统计信息 描述统计信息主要包括数据的集中趋势、离散程度和频数分析等&#xff0c;其中集中趋势主要看均值和中位数&#xff0c;离散程度可以看极值、方差、标准差等 array1 np.random.randint(1, 100, 10) …

【linux软件基础知识】如何使用 run_list 字段将任务放入就绪队列中

在给定的代码片段中,struct task_struct 表示内核中任务或进程的进程控制块 (PCB)。 run_list 字段的类型为 struct list_head,这表明它是链表实现的一部分。 run_list字段在Linux内核中常用来表示任务在调度队列中的位置,例如就绪队列或各种优先级队列。 init_task是一个…

ubuntu 22.04下面安装cuda、cudnn等的配置过程

一、正常安装ubuntu 22.04系统&#xff0c;安装以后sudo apt update,sudo apt upgrade更新软件到最新版。 二、安装cuda 到下面的地址去下载cuda离线安装包&#xff0c;根据cpu指令集架构等选择正确的选项&#xff1a; https://developer.nvidia.com/cuda-downloads?…

单链表经典算法LeetCode--203.移除链表元素(两种方法解)

1.链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;【点击即可跳转】 分析此题提供两种思路&#xff1a; 1.遍历原链表&#xff0c;将值为val的节点释放掉&#xff08;双指针法&#xff09; 定义一个pcur指针指向头节点&#xff0c;定义一个prev指针指向NULL 需要注…

Coursera吴恩达深度学习专项课程01: Neural Networks and Deep Learning 学习笔记 Week 01

Week 01 of Neural Networks and Deep Learning Course Certificate 本文是学习 https://www.coursera.org/learn/neural-networks-deep-learning 这门课的笔记 Course Intro 文章目录 Week 01 of Neural Networks and Deep Learning[0] Welcome to the Deep Learning Spec…

深入浅出HTTP/HTTPS和网络安全:HTTP/HTTPS的工作原理和常见的网络安全问题,如XSS、CSRF、SQL注入等

HTTP和HTTPS HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;安全超文本传输协议&#xff09;是浏览器和服务器之间传输信息的通信协议。两者的主要区别在于HTTPS使用了SSL/TLS协议进行了加密处理。 HTTP&#xff1a; HTTP只是一个纯文本信息传输协议&#xff…

iOS cocoapods版本降级

1. 首先卸载cocoapods ** sudo gem uninstall cocoapods ** 2. 然后查看是否卸载成功 ** pod --version ** 3. 安装新版本 ** sudo gem install cocoapods -v 1.1.1 ** 如果遇到operation 什么的错误&#xff0c;具体忘记了使用下面的命令 ** sudo gem install -n /usr/local/b…

迪杰斯特拉算法刷题笔记

理论基础&#xff1a; 求有权图中起点到某一点的最短路径问题 minDist数组&#xff1a;记录源点到某一节点的最短路程 三部曲&#xff1a; &#xff08;1&#xff09;找出距离源点相距最近的点。 &#xff08;2&#xff09;标记该点为已访问过。 &#xff08;3&#xff0…

深度学习——前馈全连接神经网络

前馈全连接神经网络 1.导入需要的工具包2.数据导入与数据观察&#xff08;1&#xff09;读取csv的文件信息&#xff1a;&#xff08;2&#xff09;训练数据前5行&#xff08;3&#xff09;打印第一个图&#xff08;4&#xff09;观察数据中的信息&#xff08;5&#xff09;查看…

数据中台:企业数字化转型的桥梁_光点科技

在数字化日益深入企业核心运营的今天&#xff0c;数据中台作为一个关键的信息化架构&#xff0c;正逐渐崭露头角&#xff0c;成为连接企业各部门、优化数据管理和推动业务创新的重要桥梁。 一、数据中台&#xff1a;连接与整合的桥梁 数据中台的核心作用在于连接与整合。传统的…

线性回归详解

在数据结构与算法的学习中&#xff0c;我们往往更多地关注于数据的存储、检索以及操作的效率问题。然而&#xff0c;当我们面对大量的数据时&#xff0c;如何从中提取有价值的信息&#xff0c;建立数学模型以解决实际问题&#xff0c;就变得尤为重要。线性回归作为一种简单而强…

【计算机毕业设计】基于SSM++jsp的公司员工信息管理系统【源码+lw+部署文档+讲解】

目录 1 绪论 1.1 研究背景 1.2 目的和意义 1.3 论文结构安排 2 相关技术 2.1 SSM框架介绍 2.2 B/S结构介绍 2.3 Mysql数据库介绍 3 系统分析 3.1 系统可行性分析 3.1.1 技术可行性分析 3.1.2 经济可行性分析 3.1.3 运行可行性分析 3.2 系统性能分析 3.2.1 易用性指标 3.2.2 可…

事件高级部分

一&#xff0c;注册事件 即给元素添加事件 1.传统注册方式 2.方法监听注册方式 事件类型&#xff1a;字符串形式&#xff0c;不用带on 可以给一个元素添加多个程序 二.删除事件 1.方式 参数见上文 三.DOM事件流 事件的传播过程叫做事件流 js代码只能获取一个阶段&#xf…

JAVA_3

JAVA_3 一、JAVA类和对象二、JAVA内存如何运转三、JAVA-constructer 一、JAVA类和对象 类包含三个内容&#xff1a; 1.属性field&#xff0c;静态特征&#xff08;数据&#xff09; 2.方法method&#xff0c;负责动态行为操作数据 3.构造器constructer,负责初始化对象&#xf…