零:认识BeanDefinition
在面向对象程序设计中,我们以"对象"来作为问题空间与解空间中一对一映射关系的抽象。BeanDefinition类就是ioc容器中,对依赖反转模式中管理的对象之间依赖关系的数据抽象,简单来说:它抽象了spring对Bean的定义,用来管理基于spring的应用中的各种对象,以及对象之间的相互依赖关系。
一:BeanFactory接口清单
BeanFactory定义了IOC容器的最基本形式,提供了IOC容器应该遵循的最基本服务契约。
getBean 方法是ioc容器的主要方法,可以获取ioc容器中管理的Bean
containsBean 判断容器中是否含有指定name的bean
isSinglton 查询指定name的bean是否为单例模式
isPrototype 查询指定name的bean是否为原型模式(多实例)
(isSinglton和isPrototype可以在BeanDefinition中通过setScope来指定)
isTypeMatch 查询指定name的Bean的class类型是否与特定的class类型匹配
getType 查询指定name的bean的class类型
getAliases 查询指定name的Bean的所有别名(返回string[]),别名可以通过BeanDefinition定义
-----------------------------------------------------------------------------------------------------
二:XmlBeanFactory
XmlBeanFactory是一个可以读取以xml文件方式定义的BeanDefinition的ioc容器
在xmlBeanFactory中初始化一个XmlBeanDefinitionReader对象,用它来处理以xml方式定义的BeanDefinition,xmlBeanFactory并不直接参与处理。
xmlBeanFactory的构造器中,我们可以看到Resourse对象,Resourse对象是spring用来封装io操作的类,在此它为xmlBeanFactory指定了XmlBeanDefinitionReader的信息来源。
XmlBeanFactory继承自DefaultListableBeanFactory,spring把DefaultListableBeanFactory作为一个默认的功能完整的ioc容器来使用,它实际包含了基本ioc容器所具有的重要功能。xmlBeanFactory在其基础上扩展出了处理xml信息的方法。
从这个我们可以看到ioc容器使用的基本过程应该是:
1:创建ioc配置文件的抽象资源。(包含BeanDefinition)
2:创建一个BeanFactory。
3:创建一个载入BeanDefinition的读取器(如XmlBeanDefinitionReader),并通过回调配置给BeanFactory。
4:讲定义好的资源位置读入配置信息,具体的解析过程由具体的读取器来完成。完成载入和注册bean信息后,就可以通过ioc容器直接使用了。
-----------------------------------------------------------------------------------------------------
三:ApplicationContext
ApplicationContext在BeanFactory的基础上添加了更多功能,可以说是一个高级形态的ioc容器,也是我们最常用的。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {...}
ApplicationContext增加的特性:
1:支持不同的信息源。从上面代码中可以看到,ApplicationContext扩展了MessageSource接口,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本应用提供服务。
2:访问资源。我们可以从不同的地方得到Bean定义资源,尤其是从不同的I/O途径获得Bean的定义信息。这一特性体现在对ResourceLoader和Resource的支持上。(ApplicationContext接口的实现类都继承了DefaultResourceLoader)
3:支持应用事件。继承ApplicationEventPublisher接口,该接口在上下文中引入了事件机制,为Bean的管理提供便利。
4:其他附加的服务。
ApplicationContext容器的设计原理
我们在研究applicationContext设计原理时,以实现类FileSystemXmlApplicationContext为例。
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {...}
上图可以看到:FileSystemXmlApplicationContext中只包含了与它自身设计相关的两项功能,而其他功能都已经由他的父类AbstractXmlApplicationContext实现了。
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
第一个功能:在FileSystemXmlApplicationContext的构造器中,调用了启动ioc容器的refresh() 方法,这个方法牵扯到ioc容器启动的一系列复杂动作,同时,对于不同的容器实现这些动作都是类似的,所以在基类(AbstractApplicationContext)中将他们封装好,此处仅进行调用。
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
另一个功能:实现了从文件系统中加载xml的Bean定义资源。这部分是他设计的具体相关内容。通过他可以为读取xml文件上保存的BeanDefinition做准备(仅是做准备,并非直接处理,因为不同的应用上下文实现对应着不同的读取beanDefinition方式),此处仅得到FileSystemResourse定位资源。
总结:
1:顶层(相对顶层)接口定义通用契约
2:其他分支接口对顶层契约进行扩展,
3:用抽象类实现接口,对接口方法进行部分实现(也可全部实现,根据需求判断)。此时,若这个抽象类的具有多个子类,则可以把子类间存在分歧的部分写成抽象方法。而多个子类中相同的部分则集中由这个抽象类来进行实现。(如果仅仅只有一个子类,那么并不需要抽象类来对接口进行过滤,可以直接用一个类来实现接口,但是考虑到系统扩展的可能性,仍然建议这样做。)
4:抽象类的子类,仅仅定义与其功能设计相关的部分,但并不对相关功能进行实现,实现功能的动作被分配到其他执行者中。(因为可能会有多种不同的执行者)