1.BeanFactory思路整理 - PickDream/LiteSpring GitHub Wiki

基本的运行流程

LiteSpring运行的起点离不开XML文件,XML文件中记录着两个基本的信息,id与class,而LiteSpring就是根据这个配置读取id->class这样类似KeyValue的信息,将这些信息用一个类实例来保存,通过这一步完成了XML信息到Java类的转换,之后通过Id值,找到XML对应的类信息,通过反射创建对象,这样就是一个最基本的流程,当然这些流程可以挤在一个Class中,但这样做终归会很混乱。

根据上述描述,我们首先应该有保存相关XML信息的类,在LiteSpring中是BeanDefinition,在最简单的情况下该类只保存id与class,信息很简单,而对外开放的应该是一个创建类实例的工厂,在这里是BeanFactory,里面至少应该有getBean方法,来找到对应类信息进行创建,而保存这些信息的数据结构是一个线程安全的Map,通过Key-Value的方式快速找到所需要的类信息,而这些类信息从哪里来?必然是通过XML文件的读取,但是如果将XML文件的读取放在一个简单BeanFactory中违背了SRP(单一职责原则),在后期的维护会造成很大麻烦,所以应该抽离出来,但是很明显,BeanFactory依赖于XML文件读取类,因为里面的Map的信息需要它来提供,我们的解决方案是在读取XML文件的XMLBeanDefinitionReader类在构造时传入一个factory的实例,并调用一个固定的方法将从XML文件中获取到的BeanDefinition类放到factory的map中去,这个方法名字叫做registerBeanDefinition,那么基本的类图应该是这样:

基本结构

这样就解决了最基本的运行流程

BeanFactory的接口方法都要暴露么?-分离接口,聚焦场景

BeanFactory的三个方法中,其中只有getBean是应该给用户开放的,用户不需要了解其他的细节,不需要知道registerBeanDefinition()这个函数到底是干什么的,所以我们应该对用户所需要的接口进行必要的隔离,用户关心的是其作为一个Bean工厂的功能,需要getBean()而其他的详细方法并不需要,因此按照如下的方式进行接口隔离。

这样就对内使用BeanDefinitionRegister,由XMlBeanDefinitionReader读取XML的数据并设置到Factory中去,对外开放的是BeanFactory 由用户使用

复杂操作流程的封装-ApplicationContext(门面)

那么有了上面的工作,现在想要从一个Factory中获取文件的步骤如下:

  • 创建一个BeanFactory
  • 创建一个XMLBeanDefinitionReader并传入创建好的BeanFactory
  • XMLBeanDefinitionReader执行读取XML文件的方法
  • 最后使用BeanFactory来获取Bean

显然,用户如果这样操作的话会即死板又麻烦,而可以引入ApplicationContext,只需要传入一个文件路径,就可以完成上述的工作。而我们先实现的是通过ClassPath方式来加载XML的 ClassPathXmlApplicationContext,在这个过程中,我们可以认为ApplicationContext依然提供Factory的功能,只是一个门面(Facade),因此ApplicationContext类应该继承Factory的接口。

这样,用户就可以直接通过ClassPathXMlApplicationContext使用BeanFactoryContext

当然,读取XML的方式有很多,例如从文件系统中读取,从网络中读取,这些不同的实现都只是体现在读取方式的不同也就是前面描述过程的第三步。

不同读取文件的方式-Resource接口的抽离

清除相同类似功能类的重复代码-模板方法模式

扩充Bean的功能,实现scope