前言:之前看过<<Spring技术内幕>>有关IOC容器的讲解,无奈Spring的容器实现挺复杂,也没看懂。前几天无意中在git hub上看到了一个模仿Spring的IOC容器实现:tiny-ioc,麻雀虽小可五脏俱全,实现了Spring IOC基本功能,对把握Spring容器的设计大有裨益。自己也跟着作者一步一步实现,基本上对Spring IOC有了一个整体上的把握,具体的实现细节还是要去看源码。今天来对前面一段的学习做个总结。
1.目录结构
2.文件说明
(1)围绕Resource的类主要解决的是容器的内容从哪里读取,也就是配置文件从哪里读、如何读取的问题。
类名 | 说明 |
Resource | 接口,资源标识,通过getInputStream()方法获取外部资源输入流。 |
UrlResource | Resource接口的一个实现,通过URL获取资源。 |
ResourceLoader | 资源加载类,通过getResource(String)方法获取Resource对象。 |
(2)围绕BeanDefinition的类主要解决的是Bean的定义问题。包括Bean的名字、属性、类型等,即如何在容器中定义一个Bean,并根据这个定义生成实例。
类名 | 说明 |
BeanDefinition | 这个类保存了Bean的定义,包括Bean的名字beanClassName,类型beanClass,属性propertyValues。propertyValues是一个PropertyValue的列表,PropertyValue包含了一个属性名name,和一个属性值Object。如果Object的类型为BeanReference类型,则表明引用了另一个Bean,需要替换为实际类型。 |
BeanDefinitionReader | 接口,定义了加载BeanDefinition的规范,loadBeanDefinitions(String)。 |
AbstractBeanDefinitionReader | 实现BeanDefinitionReader接口,规定了BeanDefintionReader的基本结构。拥有一个HashMap register,用于保存String-Defintion键值对。拥有一个ReourceLoader,用于保存资源加载器。使用时只需向loadBeanDefintions()方法传入一个资源地址,就可以调用资源加载器解析Bean定义,并将解析到的BeanDefinition保存到register中。 |
XmlBeanDefintionReader | 具体实现AbstractBeanDefinition,从xml中读取Bean定义。 |
(3)围绕BeanFactory的类主要解决的是如何实例化和装备Bean的问题。
类名 | 说明 |
BeanFactory | 接口,标识一个容易,通过getBean(String)方法获取Bean实例。 |
AbstractBeanFactory | BeanFactory接口的抽象实现类,规范容器的基本结构,并将如何实例化Bean交给子类实现,这里用到了设计模式中的模板模式。用一个<String, BeanDefinition>的beanDefintionMap来维护Bean定义。当从容器中获取Bean时,如果在容器中存在就返回,如果不存在则调用doCreateBean实例化一个。 |
AutowireCapableBeanfactory | 实现自动装配的BeanFactory。首先根据BeanDefinition中的beanClassName生成一个类实例,并将其保存在BeanDefintion中(这里是提前暴露Bean,防止属性循环依赖无法完成注入的问题),接着给这个Bean设置属性。设置属性时,遍历BeanDefinition中的PropertyValues,根据PropertyValue的name将属性值设置到对应字段,如果属性值为BeanReference类型则需要调用getBean(String)从容器中获取依赖的Bean,再进行注入。 |
(4)围绕ApplicationContext的类主要是将ResourceLoader、BeanDefinitionReader、BeanFactory的gon功能进行了封装,给外部提供一个统一的根据资源路径获取Bean的方法。
类名 | 说明 |
ApplicationContext | 接口,继承了BeanFactory,因此标识为一个容器。BeanFactory实现了如何实例化和装配Bean,并没有说明BeanDefiniton是如何加载的。这个接口将BeanFactory和BeanDefintionReader结合在了一起。 |
AbstractApplicationContext | 实现了ApplicationContext接口,规范了子类的基本结构。拥有一个BeanFactory类型的属性,getBean(String)方法的具体工作委托给BeanFactory的getBean(String)方法实现。refresh()方法规定了从哪里获取资源加载类定义,这个委托给子类实现。 |
ClassPathXmlApplicationContext | 从类路径加载资源。通过XmlDefinitionReader解析UrlResourceLoader读取到的Resource,获取BeanDefiniton后,保存到BeanFactory。 |
3.涉及的设计模式
这里的BeanFactory、BeanDefinitionReader、以及ApplicationContext都用到了模板模式。这里以BeanFactory为例,AbstractBeanFactory这个抽象类并没有实现doCreateBean这个方法,而是把这个方法交给不同的子类去实现。