Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计
1 IoC容器系列的设计:BeanFactory和ApplicatioContext
在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本的功能;
另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。
应用上下文在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。这两个容器系列,就基本满足用户对IoC容器使用的大部分需求了。
1.1 Spring的IoC容器系列
我们通常说的IoC容器,实际上代表着一系列功能各异的容器产品,是指容器的功能有大有小,有各自的特点。
在IoC容器的接口定义和实现的基础之上,Spring通过BeanDefinition来管理基于Spring的应用中的各种对象以及它们之间的相互依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。
1.2 Spring IoC容器的设计
IoC容器的接口设计图:
1.第一条接口设计主线
从BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一条主要的BeanFactory的BeanFactory设计路径。在这条设计路径中,BeanFactory定义了基本IoC容器的规范。在这个接口定义中,包括了像getBean()这样的IoC容器的基本方法。而HierarchicalBeanFactory接口在继承了BeanFactory基本接口之后,增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲IoC容器的配置功能。而在接下来的ConfigurableBeanFactory接口中,定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory()设置双亲IoC容器,通过addBeanPostProcessor()配置Bena后置处理器等等。通过这些接口设计的叠加,定义了BeanFactory就是简单IoC容器 的基本功能。
2.第二条接口设计主线
以ApplicationContext应用上下文接口为核心的接口设计,这里涉及到设计到的接口主要有,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到我们常见的WebApplicationContext或者ConfigurableApplicationContext接口。在这个接口体系中,ListableBeanFactory和HierarchicalBeanFactory两个接口,连接BeanFactory接口定义和ApplicationContext应用上下文的接口定义。在ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()接口方法;对于ApplicationContext接口,它通过继承MessageSource、ResourceLoader、ApplicationEventPublisher接口,在BeanFactory简单容器中添加了许多对高级容器的特性支持。
这里设计的是主要的接口关系,而具体的IoC容器都是在这个接口体系下实现的,比如DefaultListableBeanFactory,这个基本IoC容器就是实现了ConfigurableBeanFactory,从而成为一个精简的IoC容器的实现。像其他IoC容器,比如XmlBeanFactory,都是在DefaultListableBeanFactory的基础上做扩展,同样的,ApplicationContext的实现也是如此。
这个接口系统是以BeanFactory和ApplicationContext为核心的。而BeanFactory又是IoC容器的最基本接口,在ApplicationContext的设计中,一方面可以看到它继承了BeanFactory接口体系中的ListableBeanFactory、AutowireCapableBeanFactory、HierarchicalBeanFactory等BeanFactory的接口,具备了BeanFactory IoC容器的基本功能;另一方面通过继承MseeageSource、ResourceLoader、ApplicationEventPublisher这些接口,具备了更高级的IoC容器特性。对于ApplicationContext而言,为了在Web环境下使用它,还设计了WebApplicationContext接口,这个接口通过继承ThemeSource接口来扩充。
2 BeanFactory容器的设计原理
BeanFactory接口提供了使用IoC容器的规范。在这个基础上,Spring还提供了符合这个IoC容器接口的一系列的实现供开发人员使用。以XmlBeanFactory的实现为例来说明简单IoC容器的设计原理。如图:
在Spring中,实际上是把DefaultListableBeanFactory作为一个默认的功能完整的IoC容器来使用的。XmlBeanFactory在继承了DefaultListableBeanFactory容器功能的同时,增加了新的功能,很容易从它的名字上猜到这是一个与XML相关的BeanFactory,也就是可以说它是一个可以读取以XML文件方式定义的BeanDefinition的IoC容器。
对这些XML文件定义信息化的处理并不是由XmlBeanFactory直接完成的。在XmlBeanFactory中,初始化了一个XmlBeanDefinitionReader对象,有了这个Reader对象,那些以XML方式定义的BeanDefinition就有了处理的地方。
XmlBeanFactory的实现:
public class XmlBeanFactory extends DefaultListableBeanFactory {
//拥有一个XmlBeanDefinitionReader对象解析BeanDefinition
//将自己传给Reader对象,在Reader解析完BeanDefinition后通过一个回调配置给BeanFactory private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); //传入一个Resource定位资源 public XmlBeanFactory(Resource resource) throws BeansException { this(resource, null); } public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { super(parentBeanFactory); this.reader.loadBeanDefinitions(resource); } }
参考XmlBeanFactory的实现,我们以编程的方式使用DefaultListableBeanFactory。从中我们可以看到IoC容器使用的一些基本过程。尽管我们在应用中使用IoC容器时很少用到这样的原始方式,但是了解这个基本过程对我们很有帮助。因为编程式使用容器的过程很清楚的揭示了在IoC容器实现中的那些关键的类,比如Resource、DefaultListableBeanFactory和BeanDefinitionReader之间的相互关系,例如是如何把IoC容器的功能解耦的,又是如何结合在一起为IoC容器工作的。
编程式使用IoC容器:
ClassPathResource res = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); reader.loadBeanDefinitions(res);
这样,我们就可以使用factory对象来使用DefaultListableBeanFactory这个IoC容器了。梳理一下,大概分为一下几个步骤:
1.创建IoC配置文件的抽象资源。
2.创建一个BeanFactory,这里使用的是DefaultListableBeanFactory。
3.创建一个载入BeanDefinition的读取器,通过一个回调配置给BeanFactory。
4.从定义好的资源位置读取配置信息,具体的解析成BeanDefinitions的过程由XmlBeanDefinitionReader来完成,然后配置给BeanFactory。完成整个载入和注册Bean定义后,需要的IoC容器就建立起来了。这时候就可以直接使用IoC容器了。
XmlBeanDefinitionReader