上一篇文章中我们说到了Spring IOC提供了一个基本的JavaBean容器,通过IOC容器把获取资源的方式反转,Spring使用IOC容器管理依赖关系,将依赖注入到组件中,使依赖的管理和配置更加灵活。那么在Spring中,IOC容器具体是如何设计和实现的呢?在Spring中,IOC容器是如何体现的呢?下面我们一起学习下。
IOC容器接口设计:
在SpringIOC容器设计中,有两个主要的容器系列,一个是实现BeanFactory接口的简单容器系列,这系列容器只实现了容器的最基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态而存在。ApplicationContext应用上下文在BeanFactory的基础上,增加了很多面向框架的特性,同时对应用环境作了许多适配。
注意,这张图是ioc容器的接口设计图,我们知道接口主要用于功能的扩展,从图中我们可以看出IOC容器的设计都包含了哪些功能。
主要有两条设计主线,分别是一条以BeanFactory为主和一条以ApplicationContext为主的设计主线。ApplicationContext是在BeanFactory添加了许多特性的高级容器。
BeanFactory设计主线:从BeanFactory到HierarchicalBeanFactory再到ConfigurableBeanFactory。BeanFactory定义了基本的IOC容器的规范,包括了getBean()这样的IOC容器基本方法;继承HierarchicalBeanFactory接口,添加了getParentBeanFactory()方法,从而使BeanFactory具备了双亲IOC容器的管理功能;继承ConfigurableBeanFactory接口,主要定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory()设置双亲IOC容器,通过addBeanPostProcessor()配置Bean后置处理器等。通过这样接口设计的叠加,定义了简单IOC容器的基本功能。
ApplicationContext设计主线:从BeanFactory到ListableBeanFactory再到ApplicationContet,再到我们常用的WebApplicationContext或者ConfigurableApplicationContext接口。继承ListableBeanFactory,细化了许多BeanFactory的接口功能。同时ApplicationContext通过继承MessageSource,ResourceLoader,ApplicationEventPublisher接口,在BeanFactory简单的IOC容器基础上添加了许多高级容器的特性的支持。
当我们想实现一个具体容器时,通过实现相应的接口来完成。比如DefaultListableBeanFactory是实现了ConfigurableBeanFactory,从而成为一个简单IOC容器。
下面是我们看下两个重要的容器:BeanFactory和ApplicationContext.
BeanFactory
BeanFactory是最基本的IOC容器,提供了IOC容器的基本功能,如:getBean(String name)方法,根据名称获取Bean;containsBean(String name)让用户判断是否有包含此名称的Bean等。如接口方法所示:
public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T > T getBean(String name, Class < T > requiredType) throws BeansException; Object getBean(String name, Object...args) throws BeansException; <T > T getBean(Class < T > requiredType) throws BeansException; <T > T getBean(Class < T > requiredType, Object...args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class << ? > typeToMatch) throws NoSuchBeanDefinitionException; Class << ? > getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
Spring除了提供了一系列访问Bean的接口。我们前面说过,还提供了对该接口的一系列实现供开发者直接使用,以xmlBeanFactory为例:
从图中的继承关系,我们可以看出xmlBeanFactory通过层层继承,实现了BeanFactory的接口功能。在XmlBeanFactory中,通过Resource封装BeanDefinition的来源,然后将Resource通过构造函数传递给xmlBeanFactory,再通过XmlBeanDefinitionReader解析BeanDefinition,从定义好的资源位置读入配置信息,完成Bean的载入和注册。
因为一些原因,Spring 3.1以后已经废弃了XmlBeanFactory这个类了,现在推荐使用的是ApplicationContext。我的版本是4.3.1,所以上图中XmlBeanFactory上有横线,表示已废弃。
https://blog.csdn.net/xlecho/article/details/115828549
ApplicationContext
ApplicationContext是IOC容器的高级实现,有很多高级特性,在BeanFactory基础上添加了附加功能,如:支持不同的信息源,访问资源,支持应用事件,在ApplicationContext中提供的附加服务。
以FileSystemXmlApplicationContext为例,ApplicationContext的主要功能,已经在FileSystemXmlApplicationContext 的基类AbstractXmlApplicationContext中实现了。FileSystemXmlApplicationContext 只需要再实现自身设计的功能。
主要功能有两个:
- 如果应用直接使用FileSystemXmlApplicationContext 实例化上下文的同时,启动IOC容器的refresh()过程。代码如下:
1. public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
- 与FileSystemXmlApplicationContext具体设计相关的功能:从文件系统中加载xml的BeanDefiniton资源。代码如下:
@Override protected Resource getResourceByPath(String path) { if (path != null && path.startsWith("/")) { path = path.substring(1); } return new FileSystemResource(path); }
总结:
通过这两个容器分析我们可以看出,Spring中,BeanFactory定义了容器功能的基本规范,如获取Bean,判断Bean的类型等。同时,Spring在BeanFactory基础上进行了层层扩展,使容器的功能更加丰富,如ApplicationContext继承ResourceLoader接口,使容器可以从不同地方获取BeanDefinition资源,使用户程序可以灵活的定义BeanDefinition信息;继承MessageSource接口,使容器支持参数化和国际化等。所以我们也更清楚的理解了为什么说ApplicationContext是IOC容器的高级实现,简单来说就是ApplicationContext,在BeanFactory的基础上扩展了更多高级的功能。与BeanFactory相比,对ApplicationContext的使用是一种面向框架的使用风格,所以一般建议在开发应用时,使用ApplicationContext作为IOC容器的基本形式。
同时,Spring也为开发者提供了提供了很多IOC容器的实现,开发者可以直接拿过来用。如从文件系统中加载xml形式的BeanDefinition生成IOC容器的FileSystemXmlApplicationContext。读取注解形式的BeanDefinition生成IOC容器的AnnotationConfigApplicationContext等。
大家在阅读源码时,可以先看一下类图,通过类图中的继承关系,我们能大概猜到此容器的主要功能。
通过上面的阅读,相信读者对IOC容器的设计和功能已经有了一个基本的认识。那么IOC容器是如何初始化的呢?如何读取不同形式的BeanDefiniton,生成Bean注册到容器中的呢?请看下一篇:Spring-IOC容器初始化过程