模仿 Spring 实现一个类管理容器

概述

项目的初衷是独立作出一个成熟的有特色的IOC容器,但由于过程参考Spring太多,而且也无法作出太多改进,于是目的变为以此项目作为理解Spring的一个跳板,与网上的一些模仿Spring的框架不同,本项目主要是针对注解形式
地址是Thales

流程

在Spring中,一个bean的形成分三个大的阶段,

  1. bean的定义阶段(包含BeanDefinition的加载,解析,与注册)
  2. bean的实例化阶段(包含对象的创建,属性的注入)
  3. bean的初始化阶段(包含一些资源的初始化,譬如打开文件建立连接等等)

这只是大概的划分,关于BeanPostProcessor等后置处理并没有显式的提及.

类的设计

如果只想了解一个bean是怎么从生到死的,只需要一步步debug就好了,如果看不懂,就多debug几遍.可是如果想实现一个类似的容器,类的设计,职责的分配,接口的实现继承必然是要了解的(除非你想几个类做完所有的事)

以下是
DefaultListableBeanFactory的类图

是不是顶不住

我们再来看一张图

第一张是Spring5.0的,第二张图是Spring0.9的,所以并没有必要在一开始就引入过多的设计复杂度

我们再来看一套对比图

哪一个是0.9的,哪一个是5.0的一目了然.

说这么多的目的,是说明我们没必要一开始就奔着最完善的目标去写,可以一步步来,一步步加入功能

实现简易IOC

众所周知,SpringIoC中最基本的就是BeanFactory

我们先定义一个BeanFactory接口

//暂时就给这一个方法
public interface BeanFactory {
    /**
     * 根据名字获取Bean实例
     * @param name
     * @return
     */
    Object getBean(String name);
}

beanDefinition

由于是注解形式,我们不能再像xml那样给定一个资源文件再去解析了,而应该去扫描classPath下所有带有@Component的类,
这时候我们需要给定的参数就从文件路径变成了包路径,我们只需要扫描这个包及其子包内符合条件的类,并且将其转化为BeanDefinition再注册就好.执行这个功能的是
ClassPathBeanDefinitionScanner这个类.在这一步,就已经和传统的流程有所区别了,我们会传入一个ResourceLoader去实现具体的扫描功能(即定位),但不会再有专门的类去处理解析这一步
public interface Resource {
    File getFile();
    String getFilename();
    String getFilePath();
}
//在最初设计的时候这个抽象类似乎没有用,但考虑到以后的扩展,还是先放在这
public abstract class AbstractResource implements Resource {

    @Override
    public String getFilename() {
        return getFile().getName();
    }

    @Override
    public String getFilePath() {
        return getFile().getPath();
    }
}
//这就是最终我们实例化bean时用到的Resource类,在Spring中并没有直接用,而是通过外观模式集成了一下成为RootBeanDefinition
public class ClassPathResource extends AbstractResource {
    private final String path;

    private ClassLoader classLoader;

    private Class<?> clazz;

    public ClassPathResource(String path, ClassLoader classLoader, Class<?> clazz) {
        this.path = path;
        this.classLoader = classLoader;
        this.clazz = clazz;
    }
}
public interface ResourceLoader {
    Resource getResource(String location);
}
//此类能够实现加载多个资源
public interface ResourcePatternResolver extends ResourceLoader {
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
    List<? extends Resource> getResources(String location);
}

//这个类就是正式用于扫描的类了
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
    private final ResourceLoader resourceLoader;
    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader){
        this.resourceLoader = resourceLoader;
    }

    @Override
    public Resource getResource(String location) {
        return resourceLoader.getResource(location);
    }
//在Spring中,是通过一层层方法的包装完成包名到路径的转换再到每个文件的扫描再转换为Resource,这里暂时就先一步到位,把具体实现放在工具类里
    @Override
    public List<? extends Resource> getResources(String location) {
        Set<Class<?>> classes = ClassUtils.getClasses(location);
        List<ClassPathResource> classPathResources = new ArrayList<>();
        for (Class<?> clazz:classes) {
            classPathResources.add(new ClassPathResource("",clazz.getClassLoader(),clazz));
        }
        return classPathResources;
    }
}

但最后直接使用的并不是
PathMatchingResourcePatternResolver

而是把他作为
ClassPathBeanDefinitionScanner的一个属性,在这个类里调用.

我们得到了Resource,如何获得对应的BeanDefinition?

先考虑

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值