博客总共总结了2个方面:1是介绍了IoC的概念,2是根据Spring的IoC接口关系图,通过2条设计主线来分析Spring是如何设计和实现IoC容器的?同时也简要的分析了这张IoC接口关系图(详见图2-2)
博客首先介绍了什么是IOC容器?IOC容器可以替我们做什么?为什么需要IOC容器?它又有什么优点?然后总结了Spring是如何设计和实现IOC容器的:Spring设计了一张广泛的的接口关系图,在保证了IOC容器最基本功能规范的前提下,还提供了一系列的接口,这些接口可能在不同的环境下会被用到(比如读取不同配置信息,从不同的I/O读取配置信息,从类路径读取,从文件系统中读取等等),那么在用到的时候,只需要继承这些接口并实现,就可以实现IOC容器功能的扩展。Spring主要提供了2个主要的容器系列:BeanFactory 和 ApplicationContext,前者提供了IOC容器的基本规范的接口,比如有getBean()等方法,后者是高级实现,有着更丰富的功能。同时简要地分析了IOC容器的接口关系图以及它的设计思路
IoC(Inversion of Control),翻译过来就是控制反转。我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。如果采用普通的方法,即在每个对象中需要的时候,通过new实例化一个需要的对象,然后调用这个对象的某个方法,这样会使得我们的整个系统的这些对象之间高度耦合。
现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
如图:对象之间复杂的依赖关系
那么什么是IoC容器呢?它又可以替我们做什么?我的理解是可以把它比喻成一个第三方平台,里面存放着各种各样的实例化的对象,当我们需要的时候,直接从这个平台上拿这个对象到我们用到的地方,而不用自己去创建这个对象,给对象赋值等等一系列操作。我们只需要负责用,而不用去管这个对象是如何创建出来的。而且这样可以使得散落在系统中的各种实例化对象的操作统一集中到这个平台上,更加符合面向对象的特性。我们管这个平台叫IoC容器。为什么是容器呢?因为它里面存放着许许多多的实例化对象,就和一个杯子装了许多水一样,这个杯子就是容器,水就是对象。
其中,最常见的方式叫做依赖注入 :通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
在Spring中,Spring IoC提供了一个基本的JavaBean容器,通过IoC模式管理依赖关系,并且通过依赖注入和AOP切面增强了为JavaBean这样的POJO对象赋予事务管理,生命周期管理等基本功能。
在应用开发中,往往需要引用和调用其他组件的服务,这种依赖关系如果固化在组件设计中,就会造成依赖关系的僵化和维护难度的增加。如果使用IoC容器,将资源获取的方向反转,让IoC容器主动管理这些依赖关系,且将这些依赖关系注入到组件中,那么这样会使得这些依赖关系的适配和管理更加的灵活。
具体说到Spring IoC容器的时候,Spring IoC通过对Spring设计的IoC容器系列的实现来为多种多样的场景进行适配。换句话说,Spring设计了丰富的,各种各样的接口关系(如下图2-2) ,并且每个接口都可以有它被用到的地方,比如读取不同配置信息,从不同的I/O读取配置信息,从类路径读取,从文件系统中读取等等,然后在各式各样的场景下,对这些接口进行了实现。
我认为,这种设计思想也是一种很不错的设计模式,在保证了最基本功能的基础上,通过设计各种各样的接口,来完成各式各样的扩展功能。而且如果需要新添加一个扩展功能,只需要再设计一个接口,然后让系统继承该接口,并实现这个接口里面的方法,就可以在不改动原先的代码就完成功能的扩展。很方便很灵活!
在Spring IoC容器的设计中,我们可以看到两个主要的容器系列:BeanFactory 和ApplicationContext。前者只是实现了容器的基本功能,后者是ApplicationContext应用上下文,它作为容器的高级形态而存在。它在简单容器的基础上,增加了许多面向框架的特性,同时对应用环境作了许多适配。这两种容器可以基本满足用户对IoC容器的大多数需求了。
2-2是IoC容器的接口设计图,基本上包含了所有的接口类。
就像商品都需要有产品说明书一样,作为一个IoC容器也需要为它的具体实现指定基本的功能规范。这个功能规范的设计就表现为BeanFactory接口类,它体现了Spring为提供给用户的IoC容器所设定的最基本的功能规范。
也正如图2-2表现的,可以看到BeanFactory是最老的,其他所有接口都直接或者间接继承自它。所以只要是继承或者间接继承该接口的,那么这个类肯定就是符合最基本的功能规范的。同时,为了满足一定的应用场景,又有各种接口。每个接口都是为了适配某一个场景而产生的。如果需要实现这个应用场景,只需要继承该接口并实现相对应的方法即可。这样就可以在基本IoC容器的基础上进行扩展。
以ApplicationContext为例:
它继承了ListableBeanFactory 接口,AutowireCapableBeanFactory 接口,MessageSource 接口,ResourceLoader 接口,ApplicationEventPublisher 接口.
扩展了MessageSource接口,就可以支持不同的信息源,这些信息源的扩展功能可以支持国际化的实现,为开发多语言版本的应用提供帮助
扩展了ApplicationEventPublisher ,就引入了事件机制,这些事件与Bean的生命周期相结合,为Bean的管理提供了便利
扩展了ResourceLoader接口,我们就可以在不同的地方获得Bean定义资源。这一特性体现在对ResourceLoader和Resource的支持上。
可以看到ApplicationContext提供了许多附加的服务,功能更加丰富,对它的使用也是面向框架的风格。
光有容器还不够,这装的水从哪来呢?怎么让容器知道我们需要哪些对象以及这些对象又依赖什么对象呢?这时候就需要我们的BeanDefinition了。在程序中就表现为我们的“application.xml”。当然这只是其中一种表现形式,还有其他方法可以作为BeanDefinition.
Spring通过定义BeanDefinition来管理各种对象以及它们之间的各种相互依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。依赖反转功能都是围绕对这个BeanDefinition的处理来完成的。
下面对这张接口关系图做一个简单的分析,可以根据以下内容来理解这张接口关系图:
从接口BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory是一条主要是BeanFactory设计路线。在这条路线中,首先是BeanFactory定义了基本的IoC容器规范,然后HierarchicalBeanFactory继承了BeanFactory的基本接口之后,增加了getParentBeanFactory()这样的接口功能,使得BeanFactory具备了双亲IoC容器的管理功能。在接下来的ConfigurableBeanFactory接口中,主要定义了一些对BeanFactory的配置功能,如通过setParentBeanFactory()设置双亲IoC容器,通过addBeanPostProcessor()配置Bean后置处理器等等。通过这些接口设计的叠加,定义了BeanFactory就是简单IoC容器的基本功能:
BeanFactory->HierarchicalBeanFactory->ConfigurableBeanFactory
BeanFactory:
//判断是否包含某个name的Bean:
boolean containsBean(String name);
//获取bean:
T getBean(Class requiredType) throws BeansException;
Object getBean(String name) throws BeansException;
T getBean(String name, Class requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
/*判断bean的作用域
prototype:该作用域将单一 bean 的定义限制在任意数量的对象实例
singleton : 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
HierarchicalBeanFactory:
public interface HierarchicalBeanFactory extends BeanFactory{...}
这个接口主要包含了getParentBeanFactory()这样的方法
/**
* Return the parent bean factory, or {@code null} if there is none.
*/
BeanFactory getParentBeanFactory();
使得FactoryBean有了管理双亲IOC容器的功能.
ConfigurableBeanFactory:
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
...
}
这个接口主要定义了对BeanFactory的配置功能,比如
设置双亲IOC容器;
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
配置Bean后置处理器:
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
以ApplicationContext为核心的接口设计:
BeanFactory->ListableBeanFactory->ApplicationContext->WebApplicationContext/ConfigurableApplicationContext.
在ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()接口方法。对于ApplicationContext接口,它通过继承MessageSource,ResourceLoader,ApplicationEventPublisher接口,在BeanFactory简单IoC容器的基础上添加了许多对高级容器的特性的支持。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver{
.....
}
这张图涉及的是主要接口关系,而具体的IOC容器则是在这个接口体系下实现的。比如DefaultListableBeanFactory,这个基本IOC容器的实现就是实现了ConfigurableBeanFactory,从而成为一个简单的IoC容器的实现。像其他的IOC容器,比如XMLBeanFactory,都是在DefaultListableBeanFactory的基础上进行了扩展。同样的,ApplicationContext的实现也是如此。
这个接口系统以BeanFactory和ApplicationContext为核心。BeanFactory是最基本的接口。而ApplicationContext则通过继承了多个接口,使得它有着更高级的IOC容器的特性。对于ApplicationContext而言,为了在Web环境中使用它,还设计了WebApplicationContext接口,而这个接口通过继承ThemeSource接口来扩充功能。
感觉书中内容颇多,需要理解的东西很多,就把BeanFactory和ApplicationContext的设计原理,以及IoC容器的初始化过程放在下一篇博客中做总结~~最后欢迎大家访问我的个人站点