手写Spring2(实现 Bean 的定义、注册、获取)

news2024/11/18 5:54:42

文章目录

  • 前言
  • 本章目标
  • 一、实现
    • 1、项目结构
    • 2、BeanFactory-bean工厂
    • 3、BeanDefinition -bean定义
    • 4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry
    • 5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)
    • 6、AbstractAutowireCapableBeanFactory-实例化Bean
    • 7、DefaultListableBeanFactory-bean工厂核心实现类
  • 五、测试
    • 1、准备的测试类
    • 2、测试用例
    • 3、测试结果
  • 总结


前言

继续完善 Spring Bean 容器框架的功能开发


本章目标

1、bean的创建交给容器

2、getBean采用模板方法设计模式,指定调用过程和标准定义,控制了后续的实现者不用关心调用逻辑,按照统一方式执行

3、容器框架的类结构优化,方便后续功能的扩展


一、实现

1、项目结构

├─src
│  ├─main
│  │  ├─java
│  │  │  └─cn
│  │  │      └─ljc
│  │  │          └─springframework
│  │  │              └─beans
│  │  │                  │  BeansException.java
│  │  │                  │
│  │  │                  └─factory
│  │  │                      │  BeanFactory.java
│  │  │                      │
│  │  │                      ├─config
│  │  │                      │      BeanDefinition.java
│  │  │                      │      SingletonBeanRegistry.java
│  │  │                      │
│  │  │                      └─support
│  │  │                              AbstractAutowireCapableBeanFactory.java
│  │  │                              AbstractBeanFactory.java
│  │  │                              BeanDefinitionRegistry.java
│  │  │                              DefaultListableBeanFactory.java
│  │  │                              DefaultSingletonBeanRegistry.java
│  │  │
│  │  └─resources
│  └─test
│      └─java
│          └─springframework
│              └─test
│                  │  ApiTest.java
│                  │
│                  └─bean
│                          UserService.java

在这里插入图片描述

2、BeanFactory-bean工厂

/**
 * @desc Bean工厂
 * @Author: ljc
 * @Date: 2022/11/28 10:36
 */
public interface BeanFactory {

    Object getBean(String name) throws BeansException;

}

上一章的BeanFactory 是一个类,这里把他抽象了,变成一个接口,方便扩展


3、BeanDefinition -bean定义

/**
 * @desc Bean定义
 * @Author: ljc
 * @Date: 2022/11/28 10:35
 */
public class BeanDefinition {

    private Class beanClass;

    public BeanDefinition(Class beanClass) {
        this.beanClass = beanClass;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}

上一章Object beanClass 改为Class beanClass,bean的实例化操作可以放到容器中去处理


4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry

单例注册bean的接口

/**
 * @desc 单例注册接口定义
 * @Author: ljc
 * @Date: 2022/11/30 17:27
 */
public interface SingletonBeanRegistry {

    Object getSingleton(String beanName);

}

提供了一个获取单例bean的接口


单例注册bean的实现

/**
 * @desc 单例注册接口的实现类
 * @Author: ljc
 * @Date: 2022/11/30 17:28
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    /**
     * @desc: 单例池
     * @author: ljc
     * @date: 2022/12/7 10:57
     * @param:
     * @return:
     **/
    private Map<String,Object> singletonObjects = new HashMap<>();

    /**
     * @desc: 获取单例bean
     * @author: ljc
     * @date: 2022/12/7 10:57
     * @param: [beanName]
     * @return: java.lang.Object
     **/
    @Override
    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName);
    }

    /**
     * @desc: 入单例池
     * @author: ljc
     * @date: 2022/12/7 10:56
     * @param: [beanName, singletonObject]
     * @return: void
     **/
    protected void addSingleton(String beanName,Object singletonObject){
        singletonObjects.put(beanName,singletonObject);
    }
}

实现了获取单例bean的接口,并且定义了一个对象单例池,以及提供了添加对象到单例池的保护方法

保证单一职责,只负责处理单例Bean的处理


5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)

/**
 * @desc 抽象bean工厂类
 * @Author: ljc
 * @Date: 2022/12/7 11:10
 */
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {


    @Override
    public Object getBean(String name) throws BeansException {
        Object bean = getSingleton(name);
        if (bean != null) {
            return bean;
        }

        BeanDefinition beanDefinition = getBeanDefinition(name);
        return createBean(name, beanDefinition);
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

}

新增了2个抽象方法,getBeanDefinition和createBean;

AbstractBeanFactory 继承于DefaultSingletonBeanRegistry,获得了单例注册bean的能力,并且实现了bean工厂的getBean方法

在getBean里面只定义了调用过程(模板模式),并没有自己去实现,让实现此抽象的类去完成。

PS:
这样使用模板模式 (opens new window)的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可


6、AbstractAutowireCapableBeanFactory-实例化Bean

/**
 * @desc 实例化Bean类
 * @Author: ljc
 * @Date: 2022/12/7 13:06
 */
public abstract class  AbstractAutowireCapableBeanFactory extends AbstractBeanFactory{

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
        Object bean = null;
        try {
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        addSingleton(beanName,bean);
        return bean;
    }
}

AbstractAutowireCapableBeanFactory 本身也是一个抽象类

它只会实现属于自己的抽象方法,其他抽象方法由继承AbstractAutowireCapableBeanFactory 的类实现。

这里会有一个问题,如果是带参数的构造方法如何处理?(在源码里,其实是有一个寻找构造方法的判断处理)


7、DefaultListableBeanFactory-bean工厂核心实现类

/**
 * @desc bena工厂核心实现类
 * @Author: ljc
 * @Date: 2022/12/7 13:33
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry{

	// bean定义的缓存
    private final Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();


    @Override
    protected BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition ==null) throw new BeansException("No bean named " + beanName + " is defined");
        return beanDefinition;
    }

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

    }
}

继承于AbstractAutowireCapableBeanFactory ,拥有了创建bean、获取bean的能力

并且实现了BeanDefinitionRegistry接口的,内部实现了egisterBeanDefinition(实现了Bean定义


五、测试

1、准备的测试类

/**
 * @desc 用户服务类
 * @Author: ljc
 * @Date: 2022/11/28 10:56
 */
public class UserService {

    public void queryUserInfo(){
        System.out.println("查询用户信息");
    }

}

2、测试用例

/**
 * @desc 测试
 * @Author: ljc
 * @Date: 2022/11/28 10:57
 */
public class ApiTest {

    @Test
    public void test_BeanFactory() {
        // 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();
        
        System.out.println(userService);
        System.out.println(userService_singleton);
    }

}

测试案例主要包含了 初始化bean工厂、注册bean、获取bean。

上一章的测试用例,可以看到是通过new userService()来定义bean,现在是把UserService的class传给bean定义。

调用2次获取bean,主要是用于测试第二次获取时,是否从缓存里获取,按上述代码,结果是肯定的!

3、测试结果

查询用户信息
查询用户信息
springframework.test.bean.UserService@504bae78
springframework.test.bean.UserService@504bae78

Process finished with exit code 0

可以看到打印的对象是同一个


总结

可以看到本章节,增加了很多类和接口,为什么要设计成这样?

基于接口、抽象编程,便于扩展

松耦合,让每个类只承担自己职责的那部分,尽可能保证单一职责

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

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

相关文章

python配置环境问题记录------2022/12/07

python配置问题记录1、版本匹配的问题2、指令安装相关依赖包3、pycharm指定解释器4、运行网络模块5、总结1、版本匹配的问题 到官网下载合适的版本&#xff08;注意位数&#xff0c;我这里选的是64位&#xff09;&#xff0c;pycharm选的是21年版本的&#xff0c;太新的话会有…

【C++】异常exception

目录 一.C语言错误处理方式 1.assert(断言) 2.返回/设置错误码 二.C异常的概念与使用 1.异常的概念 2.异常的使用 三.自定义异常体系MyException 四.异常的重新抛出 五.异常安全问题 六.异常规范 七.异常的优缺点对比 一.C语言错误处理方式 一个C语言程序, 在运行期…

回归分析与相关分析的区别和联系

在本节中&#xff0c;我们将首先讨论相关性分析&#xff0c;它用于量化两个连续变量之间的关联&#xff08;例如&#xff0c;独立变量与因变量之间或两个独立变量之间&#xff09;。 最近我们被客户要求撰写关于回归分析与相关分析的研究报告&#xff0c;包括一些图形和统计输…

软件测试经验与教训

下面精选出10条&#xff0c;和大家分享。 01 测试人员是项目的前灯 一个项目就像是一次陆上旅行。有些项目很简单、很平常&#xff0c;就像是大白天开车去商店买东西。但是大多数值得开发的项目更像是夜间在山里开越野卡车&#xff0c;这些项目需要前灯&#xff0c;而测试员要照…

直播带货行业如何入局?先了解一下直播商城源码吧

直播行业的爆火已经持续了多个年头&#xff0c;直到今天&#xff0c;在人们的生活中依然有着举足轻重的地位&#xff0c;它通过多元化的方案为许多行业带来了新的思路&#xff0c;特别是与传统商业所结合的“直播电商”、“直播商城”的卖货新形式&#xff0c;让多方因此而受益…

数理化解题研究杂志社数理化解题研究编辑部2022年第30期目录

教学改革探索 信息技术下中职数学“翻转课堂”教学创新策略研究 李宇仙; 2-4《数理化解题研究》投稿&#xff1a;cn7kantougao163.com 基于高中数学核心素养的错题讲评课之探索与实践 施浩妹; 17-20 高中数学“问题导学”模式的实践研究 吴金桥; 21-23 立于神而…

【测试沉思录】21. 如何用 JMeter 编写性能测试脚本?

作者&#xff1a;宋赟 编辑&#xff1a;毕小烦 Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例…

【强化学习论文合集】十.2018智能体和多智能体系统国际联合会议论文(AAMAS2018)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

十四、SpringBoot-自动装配原理

十四、SpringBoot-自动装配原理 SpringBoot与Spring比较起来&#xff0c;优化的点主要有&#xff1a; 自动配置&#xff1a;是一个运行时&#xff08;应用程序启动时&#xff09;的过程&#xff0c;考虑了众多因素&#xff0c;才决定Spring配置应该用哪个&#xff0c;不该用哪…

软件测试基础丨测试工程师之间要善于发现闪光点——测试理念篇

测试理念有多种&#xff0c;有一些理念&#xff0c;深藏于我的心中&#xff0c; 而这些理念&#xff0c;您或许偶尔想到&#xff0c;却没有说出&#xff0c;或许您感受到了&#xff0c;却因为工作生活的忙碌&#xff0c;没有将其背后的含义想具体&#xff0c; 在此我非常愿意和…

零基础小白hadoop分布式集群环境搭建(超详细)

搭建集群所需要安装包 虚拟机、ubuntu镜像文件、jdk安装包、hadoop安装包 百度云盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ejVamlrlyoWtJRo1QQqlsA提取码&#xff1a;fcqm 本文的环境是两台windows笔记本&#xff0c;在每台笔记本上安装一个虚拟机&…

超详细的水果FL Studio21最新版更新全功能详细介绍!80项更新与改进!

万众期待的 FL Studio 21 版本将于正式发布上线&#xff0c;目前在紧锣密鼓的安排上线中&#xff0c;届时所有购买正版 FL Studio 的用户&#xff0c;都可以免费升级到21版&#xff01;按照惯例&#xff0c;本次新版也会增加全新插件&#xff0c;来帮助大家更好地创作。今天先给…

SMART原则介绍

一、SMART原则简介 什么是SMART原则? SMART原则(S=Specific、M=Measurable、A=Attainable、R=Relevant、T=Time-bound)是为了利于员工更加明确高效地工作,更是为了管理者将来对员工实施绩效考核提供了考核目标和考核标准,使考核更加科学化、规范化,更能保证考核的公正、…

五万字详解“GoF”的23种设计模式

大家好&#xff0c;我是栗筝i&#xff0c;近期我总结梳理了 “GoF”的 23 种设计模式&#xff0c;并使用 Java 对每种设计模式都进行了伪代码与 Demo 实现&#xff0c;并总结了每种设计模式的应用场景&#xff0c;优缺点&#xff0c;UML图等相关内容&#xff0c;字/词数达到了5…

Java中的String

/*** 关于java.lang.String类* 1、String表示字符串类型&#xff0c;属于引用数据类型&#xff0c;不属于基本数据类型* 2、在java中用双引号括起来的都是String对象* 3、java中规定&#xff0c;字符串是不可变的* 4、字符串存储在方法区的字符串常量池当中*/ …

单例模式(python)

一、模式定义 1. 单例模式(Singleton Pattern)&#xff1a;确保某一个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这个实例&#xff0c;这个类称为单例类&#xff0c;它提供全局访问的方法。 2. 单例模式的要点有三个&#xff1a; 某个类只能有一个实例 必须自…

[激光原理与应用-41]:《光电检测技术-8》- 白光干涉仪

目录 第1章 白光干涉仪概述 第2章 常见干涉仪 2.1 激光量块干涉仪 2.2 白光干涉测量表面形貌的系统 第1章 白光干涉仪概述 用于光在两个不同表面反射后形成的干涉条纹进行分析的设备。 干涉仪是一种对光在两个不同表面反射后形成的干涉条纹进行分析的仪器。 其基本原理就…

SpringColud——Ribbon(负载均衡)Hystrix(熔断器)

目录 1、Ribbon 1.1、什么是Ribbon&#xff08;负载均衡&#xff09; 1.2、创建两个user-service实例 1.3、开启负载均衡 2、Histrix&#xff08;熔断器&#xff09; 2.1、什么是Histrix 2.2、雪崩问题 2.3、服务降级 2.4、开启熔断 2.5、编写降级逻辑 2.6、编写降级…

顶象App加固——助力微投证券融入IOS生态

过去十年里&#xff0c;App几乎重新定义了互联网&#xff0c;如今所有人的智能手机里都有着无数个App。 以App store 为例。最新数据显示&#xff0c;当前61个国家/地区在 App Store 现存的App总数为29,085,727。其中虽包含重复的App&#xff0c;但也可见在不同国家/地区&…

毕业设计 基于STM32单片机的老人防摔倒报警系统 - 物联网 嵌入式

文章目录0 前言1 整体设计2 硬件电路3 软件设计4 跌倒检测算法5 关键代码6 最后0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉…