第二步->手撕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<>();

    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    protected 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<>();

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    @Override
    protected 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 里
以下进行测试

@Test
    public void Test_BeanFAcotyr() {
        // 1.初始化 BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 2.注册 bean
        BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);
        // 3.第一次获取 bean
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.queryUserInfo();
    }

    @Test
    public void Test_BeanFAcotyr_two() {
        // 1.初始化 BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 2.注册 bean
        BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);
        // 3.第一次获取 bean
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.queryUserInfo();
//
        // 4.第二次获取 bean from Singleton
        UserService userService_singleton = (UserService) beanFactory.getBean("userService");
        userService_singleton.queryUserInfo();
    }
查询用户信息
查询用户信息

Process finished with exit code 0

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3使用setup模式的store报错

** setup store模式 $reset方法报错 ** 顾名思义就是 使用store 使用的是setup 语法模式 不能执行$reset 方法 解决方式&#xff1a; // main.ts import { createPinia } from pinia const pinia createPinia() pinia.use(({ store }) > {const initialState JSON.pars…

JupyterLab OpenCV展示图片

JupyterLab OpenCV展示图片 方式一 注意&#xff1a;此种方式如果在远程服务器上的JupyterLab上运行&#xff0c;可能会出现错误。 import cv2# 读取图片 image cv2.imread(photo/blg.png)# 显示图片 cv2.imshow(image, image)# 等待按键&#xff0c;之后关闭所有窗口 cv2.w…

c语言题库之多个数组从两边移动向中间汇聚

文章目录 题目分析代码实现代码分析 题目 c语言题库之多个数组从两边移动向中间汇聚 呈现效果&#xff1a;输入想要输入的字符数组呈现数组从两边向中间逐渐打开的样子 分析 首先我们需要一组我们想要输入的字符数组用来展示打开的字符其次我们需要进行对数组的替换&#x…

基于STM32单片机的环境监测系统设计与实现

基于STM32单片机的环境监测系统设计与实现 摘要 随着环境污染和室内空气质量问题的日益严重&#xff0c;环境监测系统的应用变得尤为重要。本文设计并实现了一种基于STM32单片机的环境监测系统&#xff0c;该系统能够实时监测并显示室内环境的温湿度、甲醛浓度以及二氧化碳浓…

怎么把学浪课程视频下载到相册

在这个快节奏的学习时代&#xff0c;每一刻的知识获取都显得至关重要。想象一下&#xff0c;在浩瀚如海的学浪app中&#xff0c;你已经找到了那些能够点亮智慧的课程视频&#xff0c;它们不仅充满了启发&#xff0c;还是你求学旅途中的宝贵资源。但是&#xff0c;在网络不稳定或…

Unity2D 模拟手柄实现玩家移动

1&#xff0c;创建控制器UI 2&#xff0c;挂载脚本 3&#xff0c;脚本编写 基本要素 [Tooltip("玩家游戏体")]public Rigidbody2D player;[Tooltip("玩家速度")]public float speed 1f;[Tooltip("玩家动画")]public Animator animator;public …

Docker in Docker(DinD)原理与实战

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker幻想曲&#xff1a;从零开始&#xff0c;征服容器宇宙》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Docker简介 2、Docker …

MES系统与WMS集成方法(满分100学习资料)

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;老K。专注分享智能仓储物流技术、智能制造等内容。 新书《智能物流系统构成与技术实践》 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 这份文件是关于MES系…

什么是XXE漏洞,日常如何做好web安全,避免漏洞威胁

随着网络技术的不断发展&#xff0c;网站安全问题日益受到人们的关注。当前随着技术发展&#xff0c;网站存在一些常见的可能被攻击者利用的漏洞&#xff0c;而在众多网站安全漏洞中&#xff0c;XXE&#xff08;XML External Entity&#xff09;漏洞是一个不容忽视的问题。今天…

多线程·线程状态

目录 1.等待一个线程 join 2.休眠当前线程 3.线程的所有状态 4.线程的状态转换 1.等待一个线程 join 有些场景&#xff0c;我们需要控制线程的执行顺序&#xff0c;这时候就需要用到 join 了 比如&#xff1a;把大象装进冰箱要几步&#xff1f; 第一步&#xff1a;打开冰…

QT ERROR: Unknown module(s) in QT: xlsx怎么办

现象描述 QT编译c代码的时候&#xff0c;报这种QT ERROR: Unknown module(s) in QT: xlsx&#xff0c;应该如何解决&#xff1f; 这里&#xff0c;我简单记录一下自己的解决问题过程。有可能&#xff0c;对遇到同样的问题的你&#xff0c;也有所帮助 第一步 检查perl是否安装…

软考144-下午题-【试题三】:UML图-类图、用例图

一、分值与目标 题型&#xff1a; 问题一~问题三&#xff08;扩展/UML——>设计模式&#xff09; 二、UML基础知识回顾 2-1、关系 UML中有四种关系&#xff1a;依赖、关联、泛化、实现。 1、关联 关联是一种结构关系&#xff0c;它描述了一组链&#xff0c;链是对象之间的…

【计算机网络篇】数据链路层(10)在物理层扩展以太网

文章目录 &#x1f354;扩展站点与集线器之间的距离&#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 &#x1f354;扩展站点与集线器之间的距离 &#x1f6f8;扩展共享式以太网的覆盖范围和站点数量 以太网集线器一般具有8~32个接口&#xff0c;如果要连接的站点数量超过了…

JAVA毕业设计138—基于Java+Springboot+Vue的医院预约挂号小程序(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的医院预约挂号小程序(源代码数据库)138 一、系统介绍 本系统前后端分离带小程序和后台 小程序&#xff08;用户端&#xff09;&#xff0c;后台管理系统&a…

day-33 收集垃圾的最少总时间

思路 利用一个二维数组&#xff08;数组行数为3&#xff0c;分别对应三种垃圾&#xff09;记录垃圾数量&#xff0c;arr[0][i]表示第i个房子的金属、纸和或玻璃垃圾。 解题方法 将三种垃圾数量&#xff08;值与时间相同&#xff09;相加&#xff0c;最后对应垃圾车最远需要走到…

51基于单片机的温室大棚系统设计

设计摘要&#xff1a; 本设计旨在基于51单片机和蓝牙技术&#xff0c;实现一个功能完善的温室大棚系统。该系统具备以下主要功能&#xff1a;首先&#xff0c;通过连接的显示屏能够实时地显示当前的温度和湿度信息&#xff0c;方便用户了解温室内的环境变化。其次&#xff0c;…

HTML标签快速入门

文章目录 一、HTML语法规范1.1 基本语法概述1.2 标签关系 二、HTML基本结构标签2.1 第一个HTML网页2.2 基本结构标签总结 三、网页开发工具3.1 文档类型声明标签3.2 lang 语言种类3.3 字符集3.4 总结 四、HTML常用标签4.1 标签语义4.2 标题标签\<h1> - \<h6>&#…

【Linux】-Linux的实用操作:快捷键与软件安装操作、构建软连接、日期时区的设置[4]

目录 一、各类小技巧&#xff08;快捷键&#xff09; 1、ctrl c 强制停止 2、ctrl d 退出或登出 3、历史命令搜索 4、光标移动快捷键 5、清屏 二、软件安装 1、yum命令 2、apt命令 - 扩展&#xff08;ubuntu&#xff09; 三、systemctl命令 四、软连接 1、ln命令…

JAVA基础--IO

IO 什么是IO 任何事物提到分类都必须有一个分类的标准&#xff0c;例如人&#xff0c;按照肤色可分为&#xff1a;黄的&#xff0c;白的&#xff0c;黑的&#xff1b;按照性别可分为&#xff1a;男&#xff0c;女&#xff0c;人妖。IO流的常见分类标准是按照*流动方向*和*操作…

Linux开发--Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…