手写简易版Spring框架(一):Bean的定义、注册、获取

前言

讲道理,无论产品功能是否复杂,都有很大一部分程序员会写出一堆 if…else 来完成开发并顺利上线。这主要是原因没法预见当前的需求,发展是否长远、流量是否庞大、迭代是否迅速,所以在被催促上线的情况,不写 if…else 是不可能的!

那你说,既然 if…else 实现的这么快,还考虑数据结构、算法逻辑、设计模式、系统架构吗?当然这基本要看你的项目在可预见下能活多久,如果一个项目至少存活一年,并且在这一年中又会不断的的迭代。就像;你做了一个营销优惠券系统,在各种条件下发放各种类型的券,如果在最开始没有考虑好系统设计和架构模式,那么当活动频发、流量暴增、需求迭代下、最后你可能会挂在系统事故上!

我们在把系统设计的视角聚焦到具体代码实现上,你会有什么手段来实现你想要的设计模式呢?其实编码方式主要依托于:接口定义、类实现接口、抽象类实现接口、继承类、继承抽象类,而这些操作方式可以很好的隔离开每个类的基础功能、通用功能和业务功能,当类的职责清晰后,你的整个设计也会变得容易扩展和迭代。

接下来在本章节继续完善 Spring Bean 容器框架的功能开发,在这个开发过程中会用到较多的接口、类、抽象类,它们之间会有类的实现、类的继承。可以仔细参考这部分内容的开发实现,虽然并不会很复杂,但这种设计思路是完全可以复用到我们自己的业务系统开发中的。

实现结构

源码结构

涉及到的类的UML类图

UML

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

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

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

源码

BeanDefinition 定义

package com.qingyun.springframe.beans.factory.config;

/**
 * @description: Bean的定义信息,对应于spring源码中解析xml文件后获取到的Bean定义信息
 * @author: 張青云
 * @create: 2021-08-18 16:52
 **/
public class BeanDefinition {
    
    
    private Class beanClass;

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

    public Class getBeanClass() {
    
    
        return beanClass;
    }
}

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

单例注册接口定义和实现

package com.qingyun.springframe.beans.factory.config;

/**
 * @description: 单例注册表,管理和维护单例对象
 * @author: 張青云
 * @create: 2021-08-18 17:06
 **/
public interface SingletonBeanRegistry {
    
    
    /**
     * 根据提供的beanName获取单例对象
     * @param beanName 要查找的bean的名字
     * @return bean
     */
    Object getSingleton(String beanName);

    /**
     * 向单例注册表中注册一个bean对象
     * @param beanName 要注册的bean的名字
     * @param singletonObject bean单例对象
     */
    void registerSingleton(String beanName, Object singletonObject);
}

这个类比较简单主要是定义了一个获取单例对象的接口。

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: 单例注册表的实现类
 * @author: 張青云
 * @create: 2021-08-18 17:17
 **/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    
    
    //  用来保存单例对象的实例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

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

    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
    
    
        //  加锁是因为要保证get和set这两个操作整体的线程安全
        synchronized (singletonObjects) {
    
    
            Object oldObject = this.singletonObjects.get(beanName);
            if (oldObject != null) {
    
    
                throw new BeansException(beanName + "已存在");
            }
            singletonObjects.put(beanName, singletonObject);
        }
    }
}

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

抽象类定义模板方法(AbstractBeanFactory)

package com.qingyun.springframe.beans.factory.support;

import com.qingyun.springframe.beans.BeansException;
import com.qingyun.springframe.beans.factory.BeanFactory;
import com.qingyun.springframe.beans.factory.config.BeanDefinition;

/**
 * @description: BeanFactory的抽象实现类,实现了获取bean的逻辑过程
 * @author: 張青云
 * @create: 2021-08-18 18:09
 **/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
    
    
    @Override
    public Object getBean(String name) throws BeansException {
    
      // 此处应用模板方法模式
        //  先去查单例注册表
        Object singleton = getSingleton(name);
        if (singleton != null) {
    
    
            return singleton;
        }

        //  当单例注册表中不存在单例对象时,需要去获取bean的定义信息并且去创建bean
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition);

        //  将创建的bean对象添加到单例注册表中
        registerSingleton(name, bean);
        return bean;
    }

    /**
     * 获取bean的定义信息
     * @param beanName bean的名字
     * @return 定义信息
     * @throws BeansException 获取出错时的异常
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    /**
     * 根据定义信息去创建bean对象
     * @param beanName bean的名字
     * @param beanDefinition bean的定义信息
     * @return bean对象
     * @throws BeansException 出错时的异常
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}

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

实例化Bean类(AbstractAutowireCapableBeanFactory)

package com.qingyun.springframe.beans.factory.support;

import com.qingyun.springframe.beans.BeansException;
import com.qingyun.springframe.beans.factory.config.BeanDefinition;

/**
 * @description: 实现了根据BeanDefinition去创建bean的能力
 * @author: 張青云
 * @create: 2021-08-18 18:29
 **/
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);
        }
        return bean;
    }
}

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

核心类实现(DefaultSingletonBeanRegistry)

package com.qingyun.springframe.beans.factory.support;

import com.qingyun.springframe.beans.BeansException;
import com.qingyun.springframe.beans.factory.config.BeanDefinition;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: BeanFactory的核心实现类
 * @author: 張青云
 * @create: 2021-08-18 18:43
 **/
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry{
    
    
    //  用来存储bean的定义信息
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    @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 里。

项目代码Github地址:https://github.com/Zhang-Qing-Yun/mini-spring,本节代码对应的commit标识为c81ba77

欢迎标星

Guess you like

Origin blog.csdn.net/zhang_qing_yun/article/details/119788144