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

一、目标

在上一节中我们实现了一个简单的Bean容器,这次我们需要结合已经实现的Spring Bean容器进行功能完善,实现Bean容器关于Bean对象的注册和获取。
这次我们把Bean的创建交给容器,而不是像之前在调用的时候传递一个实例化好的Bean对象,另外还需要考虑单例对象,在对象的二次获取时是可以从内存中获取对象的。此外不仅要实现功能,还需要完善基础容器框架的类结构体,否则后面很难进行扩容其它的功能。

二、设计

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

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

三、实现

1、工程结构

在这里插入图片描述
Spring Bean容器类关系图,如下:
在这里插入图片描述

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

2、BeanDefinition定义

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;
    }
}
  • 在Bean定义类中已经把上节的 Object bean 替换成Class,这样就可以把Bean的实例化操作放到容器中处理了。

3、单例注册接口和实现

public interface SingletonBeanRegistry {

    /**
     * 获取单例对象
     */
    Object getSingleton(String name);

}
  • 这个类主要定义了一个获取单例对象的接口
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

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

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

    protected void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
    }
}
  • 这个类只要实现了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实例化操作。在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的实例化操作。
  • 处理完Bean对象的实例化后,直接调用addSingleton方法存放到单例对象的缓存中去。

6、核心类实现(DefaultListableBeanFactory)


```java
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继承了AbstractAutowireCapableBeanFactory类,也具备了接口BeanFactory和AbstractBeanFactory等一连串的功能实现。
  • 这个类还实现了BeanDefinitionRegistry中的registerBeanDefinition()方法,当然还有一个getBeanDefinition的实现,这个方法就是前文提过它是抽象类AbstractBeanFactory中定义的抽象方法。现在注册Bea定义和获取Bean定义就可以同时使用了,接口定义了注册,抽象类定义了获取,都集中在DefaultListableBeanFactory中的beanDefinitionMap里。

四、测试

1、事先准备

public class UserService {

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

}

2、测试用例

public class ApiTest {

    @Test
    public void test() {
        //初始化BeanFactory
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        //注册bean
        BeanDefinition beanDefinition = new BeanDefinition(UserService.class);
        beanFactory.registerBeanDefinition("userService", beanDefinition);

        //第一次获取bean
        UserService userService = (UserService) beanFactory.getBean("userService");
        userService.queryUserInfo();

        //第二次获取bean from singleton
        UserService userService_singleton = (UserService) beanFactory.getBean("userService");
        userService_singleton.queryUserInfo();
    }
}

3、测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 这里两次测试信息,一次是获取Bean是直接创建的对象,第二次是从缓存中获取的实例化对象。

参考:《手写spring:渐进式源码实践》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值