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


前言

继续完善 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

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


总结

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

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

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未闻花名丶丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值