手写Spring:第3章-实现Bean的定义、注册、获取

文章目录

一、目标:实现Bean的定义、注册、获取

💡 实现 Bean 容器关于 Bean 对象的注册和获取?

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

二、设计:实现Bean的定义、注册、获取

💡 实现Bean的定义、注册、获取?

  • 首先是在 Bean 注册的时候只注册一个类信息,而不会直接把实例化信息注册到 Spring 容器中。
  • 那么就需要修改 BeanDefinition 中的属性 ObjectClass,接下来就是在获取 Bean 对象时需要处理 Bean 对象的实例化操作以及判断当前单例对象在容器中是否已经缓存起来。
  • 首先需要定义 BeanFactory 这样一个 Bean 工厂,提供 Bean 的获取方法 getBean(String name),之后这个 Bean 工厂接口由抽象类 AbstractBeanFactory 实现。
    • 这样用 模板模式 的设计方式,可以统一设计通用核心方法的调用逻辑和标准定义,也就很好的控制了后续的实现者不用关心调用逻辑。
    • 按照统一方式执行。那么类型的继承者只需要关心具体方法的逻辑实现即可。
  • 在继承抽象类 AbstractBeanFactory 后的 AbstractAutowireCapableBeanFactory 就可以实现相应的抽象方法了。
    • 因为 AbstractAutowireCapableBeanFactory 本身也是一个抽象类,所以它只会实现属于自己的抽象方法,其他抽象方法由继承 AbstractAutowireCapableBeanFactory 的类实现。
    • 这里就体现了类实现过程中的各司其职,你只需要关心属于你的内容,不是你的内容,不要参与。
  • 另外还有块重要的知识点,就是关于单例 SingletonBeanRegistry 的接口定义实现,而 DefaultSingletonBeanRegistry 对接口实现后,会被抽象类 AbstractBeanFactory 继承。
    • 现在 AbstractBeanFactory 就是一个非常完整且强大的抽象类了,也能非常好的体现出它对模板模式的抽象定义。

三、实现:实现Bean的定义、注册、获取

3.1 工程结构

java 复制代码
spring-step-02
|-src
    |-main
    |   |-java
    |       |-com.lino.springframework
    |           |-factory
    |           |   |-config
    |           |   |   |-BeanDefinition.java
    |           |   |   |-SingletonBeanRegistry.java
    |           |   |-support
    |           |   |   |-AbstractAutowireCapableBeanFactory.java
    |           |   |   |-AbstractBeabFactory.java
    |           |   |   |-BeanDefinitionRegistry.java
    |           |   |   |-DefaultListableBeanFactory.java
    |           |   |   |-DefaultSingletonBeanRegistry.java
    |           |   |-BeanFactory.java
    |           |-BeansException.java
    |-test
        |-java
            |-com.lino.springframework.test
            |-bean
            |   |-UserService.java
            |-ApiTest.java

3.2 实现Bean的定义、注册、获取类图

  • Spring Bean 容器的功能实现,已经具备了一定的设计复杂性,这些复杂的类关系设计在各个接口定义和实现以及在抽象类继承中都有所体现。
    • BeanFactory 的定义由 AbstractBeanFactory 抽象类实现接口的 getBean 方法。
    • AbstractBeanFactory 又继承实现了 SingletonBeanRegistryDefaultSingletonBeanRegistry 类。这样 AbstractBeanFactory 抽象类就具备了单例 Bean 的注册功能。
    • AbstractBeanFactory 中又定义了两个抽象方法:getBeanDefinition(String beanName)createBean(String beanName, BeanDefinition beanDefinition),这两个抽象方法分别由 DefaultListableBeanFactoryAbstractAutowireCapableBeanFactory 实现。
    • 最终 DefaultListableBeanFactory 还会继承抽象类 AbstractAutowireCapableBeanFactory 也就可以调用抽象类中的 createBean 方法了。
  • 所有的实现都以职责划分、共性分离以及调用关系定义为标准搭建的类关系。

3.3 定义Bean异常

BeansException.java

java 复制代码
package com.lino.springframework;

/**
 * @description: 定义 Bean 异常
 */
public class BeansException extends RuntimeException {

    public BeansException(String msg) {
        super(msg);
    }

    public BeansException(String msg, Throwable cause) {
        super(msg, cause);
    }
}

3.4 BeanDefinition定义和注册

3.4.1 BeanDefinition定义

BeanDefinition.java

java 复制代码
package com.lino.springframework.factory.config;

/**
 * @description: Bean 对象信息定义
 */
public class BeanDefinition {

    /**
     * bean对象
     */
    private Class beanClass;

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

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}
  • Bean 定义类中把 Object 替换为 Class,这样就可以把 Bean 的实例化操作放到容器中处理了。

3.4.2 BennDefinition定义注册接口

BeanDefinitionRegistry.java

java 复制代码
package com.lino.springframework.factory.support;

import com.lino.springframework.factory.config.BeanDefinition;

/**
 * @description: Bean 定义注册接口
 */
public interface BeanDefinitionRegistry {
    /**
     * 向注册表中注册 BeanDefinition
     *
     * @param beanName       Bean 名称
     * @param beanDefinition Bean 定义
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
}
  • Bean 定义注册接口只有一个接口方法,就是向注册表中注册 BeanDefinition

3.5 单例注册接口定义和实现

3.5.1 单例注册接口

SingletonBeanRegistry

java 复制代码
package com.lino.springframework.factory.config;

/**
 * @description: 单例 Bean 注册表
 */
public interface SingletonBeanRegistry {

    /**
     * 返回在给定名称下注册的(原始)单例对象
     *
     * @param beanName 要查找的bean的名称
     * @return 返回注册的单例对象
     */
    Object getSingleton(String beanName);

    /**
     * 注册单例对象
     *
     * @param beanName        Bean 对象名称
     * @param singletonObject Bean 对象
     */
    void registerSingletonBean(String beanName, Object singletonObject);
}
  • 这个类比较简单,主要是定义了一个获取单例对象和注册单例对象的接口。

3.5.2 单例注册接口的实现

DefaultSingletonBeanRegistry.java

java 复制代码
package com.lino.springframework.factory.support;

import com.lino.springframework.factory.config.SingletonBeanRegistry;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 通用的注册表实现
 */
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

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

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

    @Override
    public void registerSingletonBean(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
    }
}
  • DefaultSingletonBeanRegistry 主要实现 getSingleton 方法和 registerSingletonBean 方法。

3.6 抽象类定义模板方法

3.6.1 Bean工厂接口

BeanFactory.java

java 复制代码
package com.lino.springframework.factory;

import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: 定义 Bean 工厂接口
 */
public interface BeanFactory {
    /**
     * 返回 Bean 的实例对象
     *
     * @param name 要检索的bean的名称
     * @return 实例化的 Bean 对象
     * @throws BeansException 不能获取 Bean 对象,抛出异常
     */
    Object getBean(String name) throws BeansException;
}

3.6.2 抽象Bean工厂基类,定义模板方法

AbstractBeanFactory.java

java 复制代码
package com.lino.springframework.factory.support;

import com.lino.springframework.BeansException;
import com.lino.springframework.factory.BeanFactory;
import com.lino.springframework.factory.config.BeanDefinition;

/**
 * @description: 抽象的 Bean 工厂基类,定义模板方法
 */
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);
    }

    /**
     * 获取 Bean 对象
     *
     * @param beanName 要检索的bean的名称
     * @return Bean 对象
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName);

    /**
     * 创建Bean对象
     *
     * @param beanName       要检索的bean的名称
     * @param beanDefinition Bean对象
     * @return 实例化的Bean对象
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition);
}
  • AbstractBeanFactory 首先继承了 DefaultSingletonBeanRegistry,也就具备了使用单例注册类方法。
  • 接下来很重要的一点是关于接口 BeanFactory 的实现。
    • 在方法 getBean 的实现过程中可以看到,主要是对单例 Bean 对象的获取以及在获取不到时需要拿到 Bean 的定义做相应 Bean 实例化操作。
    • 那么 getBean 并没有自身的去实现这些方法,而是只定义了调用过程以及提供了抽象方法,由实现此抽象类的其他类做相应实现。
  • 后续继承抽象类 AbstractBeanFactory 的类有两个。
    • 包括:AbstractAutowireCapableBeanFactoryDefaultListableBeanFactory,这两个类分别做了相应的实现处理。

3.6.3 实例化Bean类

AbstractAutowireCapableBeanFactory.java

java 复制代码
package com.lino.springframework.factory.support;

import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;

/**
 * @description: 实现默认bean创建的抽象bean工厂超类
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory {

    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) {
        Object bean = null;
        try {
            bean = beanDefinition.getBeanClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        registerSingletonBean(beanName, bean);
        return bean;
    }
}
  • AbstractAutowireCapableBeanFactory 类中实现了 Bean 的实例化操作 newInstance
  • 在处理完 Bean 对象的实例化后,直接调用 registerSingletonBean 方法存放到单例对象的缓存中去。

3.6.4 核心类:默认的Bean工厂实现

DefaultListableBeanFactory.java

java 复制代码
package com.lino.springframework.factory.support;

import com.lino.springframework.BeansException;
import com.lino.springframework.factory.config.BeanDefinition;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 默认的Bean工厂实现类
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    @Override
    protected BeanDefinition getBeanDefinition(String beanName) {
        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) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }
}
  • DefaultListableBeanFactorySpring 的源码中也是一个非常核心的类。
  • DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory 类,也就具备了接口 BeanFactoryAbstractBeanFactory 等一连串的功能实现。
  • 除此之外这个类还实现了接口 BeanDefinitionRegistry 中的 registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 方法。
    • 还会看到一个 getBeanDefinition 的实现,这个方法是抽象类 AbstractBeanFactory 中定义的抽象方法。现在注册 Bean 定义与获取 Bean 定义就可以同时使用了。
    • 接口定义了注册,抽象类定义了获取,都集中在 DefaultListableBeanFactory 中的 beanDefinitionMap 里。

四、测试:实现Bean的定义、注册、获取

ApiTest.java

java 复制代码
@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();

    // 3.第二次获取bean
    UserService userService_singleton = (UserService) beanFactory.getBean("userService");
    userService_singleton.queryUserInfo();
}
  • 在此次的单元测试中处理包括:Bean 工厂、注册 Bean、获取 Bean 三个步骤,还额外增加了一次对象的获取和调用。
    • 这里主要测试验证单例对象是否正确的存放到了缓存中。
  • 此时,我们把 UserService.class 传递给了 BeanDefinition

测试结果

java 复制代码
查询用户信息查询用户信息
  • 这里会有两次测试信息,一次是获取 Bean 时直接创建的对象,另外一次是从缓存中获取的实例化对象。
  • 此外从调试的截图中看出第二次获取单例对象,是从内存中获取的。

五、总结:实现Bean的定义、注册、获取

  • Spring Bean 容器的实现类中要重点关注类之间的职责和关系,几乎所有的程序功能设计都离不开接口、抽象类、实现、继承。
    • 而这些不同特性类的使用就可以非常好的隔离开类的功能职责和作用范围。
相关推荐
Java探秘者11 分钟前
Maven下载、安装与环境配置详解:从零开始搭建高效Java开发环境
java·开发语言·数据库·spring boot·spring cloud·maven·idea
攸攸太上12 分钟前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
2301_7869643617 分钟前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
2303_8120444620 分钟前
Bean,看到P188没看了与maven
java·开发语言
苹果醋321 分钟前
大模型实战--FastChat一行代码实现部署和各个组件详解
java·运维·spring boot·mysql·nginx
秋夫人23 分钟前
idea 同一个项目不同模块如何设置不同的jdk版本
java·开发语言·intellij-idea
m0_6640470228 分钟前
数字化采购管理革新:全过程数字化采购管理平台的架构与实施
java·招投标系统源码
aqua35357423581 小时前
蓝桥杯-财务管理
java·c语言·数据结构·算法
Deryck_德瑞克1 小时前
Java网络通信—TCP
java·网络·tcp/ip
砥砺code1 小时前
【2024版本】Mac/Windows IDEA安装教程
java