【手撸Spring】02 实现Bean的定义、注册、获取

全面详解 ImportBeanDefinitionRegistrar:从 Bean 定义到动态注册的底层实现 Bean 定义的本质定义:Bean 定义是 Spring 容器的构建Bean实例的蓝图,它不包含 Bean 实例本身,而是描述如何创建 Bean的元数据。生产者声明式:通过@Component@Bean、XML<bean>标签等,由 Spring 自动解析生成。编程式:通过或直接操作手动构建。核心内容// Bean 的类名(如 UserService)// 构造参数// 属性值// 作用域(singleton/prototype)// 是否延迟初始化。 阅读详情

运用设计模式,实现 Bean 的定义、注册、获取

目标

在上一章节 创建简单的Bean容器 我们初步依照 Spring Bean 容器的概念,实现了一个粗糙版本的代码实现。那么本章节我们需要结合已实现的 Spring Bean 容器进行功能完善,实现 Bean 容器关于 Bean 对象的注册和获取。

这一次我们把 Bean 的创建交给容器,而不是我们在调用时候传递一个实例化好的 Bean 对象,另外还需要考虑单例对象,在对象的二次获取时是可以从内存中获取对象的。此外不仅要实现功能还需要完善基础容器框架的类结构体,否则将来就很难扩容进去其他的功能了。

设计

鉴于本章节的案例目标,我们需要将 Spring Bean 容器完善起来,首先非常重要的一点是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到 Spring 容器中。那么就需要修改 BeanDefinition 中的属性 Object 为 Class,接下来在需要做的就是在获取 Bean 对象时需要处理 Bean 对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来了。

在这里插入图片描述

  • 首先我们需要定义 BeanFactory 这样一个 Bean 工厂,提供 Bean 的获取方法 getBean(String name),之后这个 Bean 工厂接口由抽象类 AbstractBeanFactory 实现。这样使用模板模式 (opens new window)的设计方式,可以统一收口通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑,按照统一方式执行。那么类的继承者只需要关心具体方法的逻辑实现即可。
  • 那么在继承抽象类 AbstractBeanFactory 后的 AbstractAutowireCapableBeanFactory 就可以实现相应的抽象方法了,因为 AbstractAutowireCapableBeanFactory 本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承 AbstractAutowireCapableBeanFactory 的类实现。这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。这一部分内容我们会在代码里有具体的体现
  • 另外这里还有块非常重要的知识点,就是关于单例 SingletonBeanRegistry 的接口定义实现,而 DefaultSingletonBeanRegistry 对接口实现后,会被抽象类 AbstractBeanFactory 继承。现在 AbstractBeanFactory 就是一个非常完整且强大的抽象类了,也能非常好的体现出它对模板模式的抽象定义。接下来我们就带着这些设计层面的思考,去看代码的具体实现结果

实现

1、工程结构

small-spring-step-02
└── src
    ├── main
    │   └── java
    │       └── cn.strongwind.springframework.beans
    │           ├── factory
    │           │   ├── config
    │           │   │   ├── BeanDefinition.java
    │           │   │   └── SingletonBeanRegistry.java
    │           │   ├── support
    │           │   │   ├── AbstractAutowireCapableBeanFactory.java
    │           │   │   ├── AbstractBeanFactory.java
    │           │   │   ├── BeanDefinitionRegistry.java
    │           │   │   ├── DefaultListableBeanFactory.java
    │           │   │   └── DefaultSingletonBeanRegistry.java
    │           │   └── BeanFactory.java
    │           └── BeansException.java
    └── test
        └── java
            └── cn.strongwind.springframework.test
                ├── bean
                │   └── UserService.java
                └── ApiTest.java

容器类关系图,
在这里插入图片描述
虽然这一章节关于 Spring Bean 容器的功能实现与 Spring 源码中还有不少的差距,但以目前实现结果的类关系图来看,其实已经具备了一定的设计复杂性,这些复杂的类关系设计在各个接口定义和实现以及在抽象类继承中都有所体现,例如:

  • BeanFactory 的定义由 AbstractBeanFactory 抽象类实现接口的 getBean 方法
  • 而 AbstractBeanFactory 又继承了实现了 SingletonBeanRegistry 的DefaultSingletonBeanRegistry 类。这样 AbstractBeanFactory 抽象类就具备了单例 Bean 的注册功能。
  • AbstractBeanFactory 中又定义了两个抽象方法:getBeanDefinition(String beanName)、createBean(String beanName, BeanDefinition beanDefinition) ,而这两个抽象方法分别由 DefaultListableBeanFactory、AbstractAutowireCapableBeanFactory 实现。
  • 最终 DefaultListableBeanFactory 还会继承抽象类 AbstractAutowireCapableBeanFactory 也就可以调用抽象类中的 createBean 方法了。

2、BeanDefinition 定义

public class BeanDefinition {

    private Class beanClass;

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

  • 在 Bean 定义类中已经把上一章节中的 Object bean 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。如果你有仔细阅读过上一章并做了相应的测试,那么你会发现 Bean 的实例化操作是放在初始化调用阶段传递给 BeanDefinition 构造函数的。

3、单例注册接口定义和实现

public interface SingletonBeanRegistry {

    Object getSingleton(String beanName);

}

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    private Map<String, Object> singletonObjects = new HashMap<>();

    @Override
    public Object getSingleton(String beanName) {
        return singletonObjects.get(beanName);
    }

    protected void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
    }

}

  • 在 DefaultSingletonBeanRegistry 中主要实现 getSingleton 方法,同时实现了一个受保护的 addSingleton 方法,这个方法可以被继承此类的其他类调用。包括:AbstractBeanFactory 以及继承的 DefaultListableBeanFactory 调用。

4、抽象类定义模版方法(AbstractBeanFactory)

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;

}

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

5、实例化Bean类(AbstractAutowireCapableBeanFactory)

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 类中实现了 Bean 的实例化操作 newInstance,其实这块会埋下一个坑,有构造函数入参的对象怎么处理?可以提前思考
  • 在处理完 Bean 对象的实例化后,直接调用 addSingleton 方法存放到单例对象的缓存中去。

6、核心类实现(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
    public 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;
    }

}

  • DefaultListableBeanFactory 在 Spring 源码中也是一个非常核心的类,在我们目前的实现中也是逐步贴近于源码,与源码类名保持一致。
  • DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactory 和 AbstractBeanFactory 等一连串的功能实现。所以有时候你会看到一些类的强转,调用某些方法,也是因为你强转的类实现接口或继承了某些类。
  • 除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法,当然你还会看到一个 getBeanDefinition 的实现,这个方法我们文中提到过它是抽象类 AbstractBeanFactory 中定义的抽象方法。现在注册Bean定义与获取Bean定义就可以同时使用了,是不感觉这个套路还蛮深的。接口定义了注册,抽象类定义了获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里
2、Spring手写系列-实现 Bean 的定义、注册、获取 本文通过手写 Spring Bean 容器的关键源码,详细解析了其核心设计思想和实现方式。通过这种逐步实现的方式,读者可以更好地理解 Spring 框架的设计理念,包括接口与实现的分离、模板方法模式、单例模式的应用等。这些设计不仅保证了系统的灵活性和可扩展性,同时也使得框架能够应对复杂的业务场景。在实际开发中,掌握这些设计思想将对构建稳定、可维护的系统具有重要的指导意义。 阅读详情

相关推荐

Spring如何进行动态注册Bean

BeanFactoryPostProcessor,BeanDefinitionRegistryPostProcessor,ImportBeanDefinitionRegistrar这三个类都可以进行BeanDefinition的添加,修改等操作。

u013127325的博客 1197

《手撸Spring》02-运用设计模式,实现Bean的定义、注册、获取

运用模板模式,实现Spring Bean的定义、注册、获取

LBL_lin的博客 593

Spring中Bean定义的注册流程

总的来说组件有委托类、后置处理器、解析器、包扫描器、资源加载/读取器、注册器、BeanFactory等组件,Spring的Bean定义注册流程如此,Bean初始化也差不多,包括MyBatis的初始化也用到其中的部分设计。图中主要是组件内部调用以及组件间的调用流程,当然在调用前如果非静态操作的话都是要做如构造初始化的。

qq_57756904的博客 1867

五分钟,手撸一个Spring容器

五分钟,手撸一个Spring容器,原来Spring最核心的部分就这些……

三分恶的博客 9557

避开PSRR仿真三大坑:用Cadence psspxf分析分频器时,这些设置错了白忙活

本文深入探讨了使用Cadence psspxf工具进行分频器PSRR仿真时常见的三大技术陷阱,包括扰动信号参数设置、收敛性优化和后处理信号提取。通过详细的参数推荐和实战技巧,帮助工程师避免仿真误差,提升PSRR分析效率与准确性,特别适用于16分频器等数字-模拟混合电路设计。

weixin_29258297的博客 301

【计算机组成原理】实验4:单周期CPU(Verilog)中海大

【计算机组成原理】实验4:单周期CPU

m0_63023532的博客 3660

【手撸IM】非 Springboot 项目实现自定义注解 Bean 注入

介绍如何使用自定义注解在非 Spring Boot 项目中实现 Bean 自动注入及管理。

bossfriday - 个人博客 967

OpencvSharp学习笔记(一):图片的打开,保存灰度化,保存

近来萌生了学习OpenCv的想法,经过度娘得知老夫会的C#不能直接用OpenCv,只能用他的儿子OpenCvSharp与EmguCV,奈何奈何,这两玩意的资料少的出奇,只能慢慢的摸索了,EmguCV先不说,老夫找到了牛批的资料,先摸索OpencvSharp吧 首先打开VS通过Nuget安装 选择版本后点击安装就OK了. 安装完成后,引用里面就有以下的玩意儿了… 废话不多说了,在写程序前先 using OpenCvSharp 图片打开,灰度化,保存代码如下: static void Main(strin

猥琐de专注 7188

手撸spring源码分析IOC实现原理

spring源码

一条菜菜鱼 2537

Python爬虫实战:用Selenium+ChromeDriver批量抓取政府网站政策文件(附完整代码)

本文详细介绍了使用Python的Selenium和ChromeDriver进行政府网站政策文件批量抓取的实战技巧。从环境配置、动态页面元素定位到分页机制破解和反爬虫策略,提供了完整的解决方案和代码示例,帮助开发者高效获取结构化政策数据。

weixin_42531710的博客 266

STM32F103C8T6驱动DM542步进电机:从CubeMX配置到按键控制的全流程避坑指南

本文详细介绍了如何使用STM32F103C8T6通过CubeMX配置驱动DM542步进电机的全流程,包括PWM频率计算、GPIO模式选择及按键控制实现。重点解决了常见硬件连接错误、PWM参数配置及加减速算法优化,帮助开发者快速搭建稳定的电机控制系统。

weixin_42741930的博客 308

Spring手撸源码系列-实现bean定义、注册、获取、单例bean

上一章节的bean定义以及注册获取实现的简单,只有一个类就完成了这些功能,但是不容易扩展以及安全性的问题,这一章节就需要考虑涉及类之间的关联,就会复杂一些。 上一章节是自己创建了实例bean传给了容器,这一章节就需要模拟Spring的方式容器创建 ...

dfBeautifulLive的博客 892

SDM660电源部分配置:

SDM660电源部分配置: Panel power supplies 1、Reference power supplies Description Name Regulator Voltage (V) Panel power supply 0 vddio PMIC 660/L11 1.8 Panel power supply 1 Lab PMIC 660/lab 4.6 Panel power s...

weixin_41811215的博客 4728

Spring IOC 第2章 实现 Bean 的定义、注册、获取

Spring IOC 实现 Bean 的定义、注册、获取案例

小凯的博客 1364

美军利用MANET技术实现无人作战单元协同作战

本文首先介绍了移动自组织网络 (MANET)以及Wave Relay®波形中继技术,并探讨了波形中继MANET平台在美空军ABMS项目等军事方面的运用情况。

guanyifu9的博客 853

aic8800出现insmod: can‘t insert ‘/lib/modules/4.9.191/aic8800_fdrv.ko‘: No such device

2、如果单独编译wifi驱动,则把CONFIG_PLATFORM_UBUNTU?= y都改为CONFIG_PLATFORM_ALLWINNER?1、如果把wifi驱动嵌入到内核编译,则在makefile中加入这一句。后面再修改对应平台的交叉编译链和内核吗路径等。

mantouyouyou的博客 510

BeanDefinitionRegistryPostProcessor——动态注册Bean到Spring容器

我宁愿靠自己的力量,打开我的前途,而不愿求有力者垂青。——《悲惨世界》 1、理论 一般如果想将类注册到spring容器,让spring来完成实例化,常用方式如下: xml中通过bean节点来配置; 使用@Service、@Controller、@Conponent等注解。 最近在研究通过Spring初始化时扫描自定义注解,查到了通过实现BeanDefinitionRegistryPostP...

跨语言,跨平台,跨应用 2万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

手写spring02- 实现bean的定义 注册 获取

文章目录目标设计实现BeanDefinition 的定义单例注册接口的定义与实现定义bean工厂 BeanFactory抽象类定义模板方法 AbstractBeanFactory实例化Bean类 AbstractAutowireCapableBeanFactory核心类实现(DefaultListableBeanFactory)测试 目标 此文中实现了spring容器的粗略的版本 https://javaweixin6.blog.youkuaiyun.com/article/details/124256888 此节要实

Java持续实践 917

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Spring中Bean对象的定义、注册和获取

BeanDefinition:这是一个接口,定义了一个Bean的所有配置信息,包括Bean的类名、是否为单例、Bean的构造函数和构造参数、Bean的属性等。DefaultListableBeanFactory:这是Spring的核心类,它是一个默认的Bean工厂,同时也是一个Bean定义的注册表,我们可以使用它来注册Bean定义。BeanDefinitionBuilder:这是一个工具类,用于创建BeanDefinition。

qq_43456605的博客 1014

Spring 02-Spring Bean的定义

Spring容器中Bean的定义

2401_84606589的博客 1709

【小家Spring】Spring的Bean定义注册中心BeanDefinitionRegistry详解

前言 Spring Framework最重要的一个概念就是Bean,而Spring Bean定义是需要扫描、注册来实现统一的管理的。 前面已经介绍了Spring容器的启动过程、分类、Bean定义信息的详解等。但是发现有读者留言问了Bean定义注册中心得一些问题,因此本文主要是讲解BeanDefinitionRegistry BeanDefinitionRegistry BeanDefinition...

架构师:通透,才能写出好代码! 1万+

《手撸Spring》-实现一个简单的Bean容器

通过手撸Spring学习,更好的理解源码底层的实现。

LBL_lin的博客 1139

Spring 手动注册bean

一般情况下,我们Spring应用中的bean都是通过注解或者xml注入到容器中的,有些情况下我们可能想手动往容器中注入bean,即编程方式注入bean。 本文所使用源码包版本:spring-beans-5.0.5.RELEASE. 如何注册? Spring 中用BeanDefinition接口描述一个bean,Spring容器中用Map<Strin...

灵颖桥人的博客 1万+

Spring Bean 的定义和注册详解

这些对象构成了应用程序的主干,并由 Spring IoC 容器负责实例化、配置、组装和管理它们的整个生命周期。Spring 提供了多种注册 Bean 的方式, 包括 XML 配置、Java 注解、Java 配置类和编程式注册。Bean 注册是将 Bean 定义添加到 Spring 容器的过程。Bean 定义描述了如何创建和配置一个 Bean。实例化、配置和初始化 Bean, 并管理它们的整个生命周期。注解标注方法,方法的返回值就是 Bean 实例。该 Bean 所依赖的其他 Bean。

专注于技术分享 1518

【 手撕Java源码专栏 】Spirng篇之手撕SpringBean:(包含Bean扫描、注册、实例化、获取)

本文先演示原生 Spring Bean 扫描与创建,剖析其扫描、注册、实例化、获取流程;再详述手写 Spring 框架的实现思路与核心代码,对比两者差异,助力理解 Spring 容器核心原理与反射等技术应用。

Varin 1227

Spring 源码解读:自定义实现Bean定义的注册与解析

Bean定义的注册与解析是Spring框架依赖注入的关键环节。本文将通过自定义实现Bean定义的注册与解析机制,探索其工作原理。我们还将对比Spring中的`BeanDefinition`和`BeanDefinitionRegistry`接口,帮助读者深入理解Spring容器的核心机制。

捕风捉你 · 星桥API接入与大模型实战 1295
上一篇: 代码随想录day6
下一篇: 代码随想录day7
Strongwind_
博客等级 码龄7年 139粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值