Spring核心——上下文与IoC

前面3篇分别介绍了IoC容器与Bean的关系Bean与Bean之间的关系以及Bean自身的控制和管理。在了解Spinrg核心模式时,必定要谨记他的基本工做元素就是IoC容器和Bean,全部的功能是围绕着这2者展开的。要实现的内容无非就是经过设计模式来解决IoC与Bean的关系Bean与Bean的关系IoC与IoC的关系,以及对Ioc和Bean的控制html

IoC控制入口

看完整个Spring CoreAPI Doc,你也不会发现任何一个名为IoC的类或者接口。惟一一个提到IoC这个词的是spring-beans工程下关于org.springframework.beans.factory这个包的介绍——"The core package implementing Spring's lightweight Inversion of Control (IoC) container."。实际上Spring核心框架将对IoC容器的控制都交给了BeanFactoryApplicationContext两个接口。java

这个2个接口有什么关系吗?一个叫Factory,一个叫Context,概念上彻底是两码事,前者是建立模式的FLAG,后者是行为模式的FLAG。而且在工程结构上,一个属于spring-beans,另一个属于spring-context。不过仔细看会发现ApplicationContext继承自BeanFactory的派生接口 ListableBeanFactory、HierarchicalBeanFactory )。要想理解他们的关系和做用,还得一个一个来讲。面试

factory包中的接口

在Spring核心工程中,BeanFactory及其派生被定义为“Ioc容器的轻量级实现”。这也是Spring最基础的IoC容器和Bean的管理接口。factory包中主要涉及5个接口BeanFactory、ListableBeanFactory、HierarchicalBeanFactory、ConfigurableBeanFactory和ConfigurableListableBeanFactory初来咋到看到这5个接口八成懵逼,少数牛逼的码友估计能从名字猜想出他们的功能。其实他们有很清晰的层次结构,一层继承一层,一层扩展一层的功能。spring

(图片来源于他人博客,若有侵权请告知)编程

BeanFactory是IoC容器最基本的功能,他就是前面文章中一直提到的IoC设计模式的具体实现——处理IoC与Bean,Bean与Bean的关系。能够理解BeanFactory自身就是一个IoC容器,而后提供了getter、is、contains接口来获取和判断Bean的状态。对于单例或多例,BeanFactory只提供了BeanFactory::isSingleton和BeanFactory::isPrototype2个方法,这也是为何我在设计模式与IoC一文中会说从设计模式的角度来讲,Bean除了工厂方法外,只涉及singletonprototype2个建立模式。设计模式

ListableBeanFactory继承自BeanFactory接口。看方法会发现,BeanFactory只提供单个Bean的操做,而ListableBeanFactory都是支持列表操做,好比获取Bean的总数、获取Bean的name列表、经过Bean的Type获取Bean的列表、根据注解获取Bean的列表等。从字面上的Listable也能够看出来其是在基本Factory的基础上扩展了相同类型、相同名称Bean的功能。网络

HierarchicalBeanFactory从字面上就应该大概知道他的做用的解决层级问题,提供子父容器的管理方法。框架

再往下就是ConfigurableListableBeanFactory接口,这个接口提供的IoC控制功能,从子字面Configurable来看意思就是能够配置的。顶层的几个接口(BeanFactory、ListableBeanFactory)都没提供Setter或Creater的功能,而ConfigurableListableBeanFactory集成的3个接口ListableBeanFactory、AutowireCapableBeanFactor、ConfigurableBeanFactory提供了Setter、Creater的功能。实际上ConfigurableListableBeanFactory就是提供了Beans的“增改”功能,以及一些附加的依赖控制。socket

网上关于BeanFactory及其派生结构介绍的资料不少,大部分都是从源码的角度详细说明他们之间的依存关系。不过从使用者的角度,实际上从整体上去了解他的组合模式思路,比你一个一个的去看源码有意义得多,更况且就算你如今看了源码,一年不碰你还能记得?总不能每天还复习吧?看源码主要是要理解做者针对实现所用设计模式。固然你要是要参加什么面试的话,还真得复习复习。记得之前我做为面试官曾叫别人当场写出ConfigurableListableBeanFactory的继承关系。如今想一想当时本身有多脑残,被面试的那些小哥估计想拍我吧?开发能力的好坏是一种思惟方式,而不是谁记得2个 new String("A")到底建立了几个String实例,或者Integer的0到128会被预设。学习

实际上进通过多年的发展,Spring Core 的BeanFactory这块已经发生了屡次改变。从最基础的BeanFactory到ConfigurableListableBeanFactory层层向下推动全是接口或抽象类,每个接口都在父接口的基础上包装了的新的接口方法。经过多层继承,官方的代码中只有一个名为DefaultListableBeanFactory的类将全部的接口功能都实现了,而后XmlFactory又继承实现了资源读写的功能。XmlFactory并无多少代码,Ioc的核心功能都在DefaultListableBeanFactory。

从设计模式上来讲,很难去定义这么多接口派生可是一个实现类提供全部功能的模式到底算什么。我我的认为这很像外观模式(Facade Pattern)和装饰模式(Decorator Pattern)结合。现实中咱们没也不必像教科书似的模式来理解应用。下面解释这个思路。

首先咱们来看看效果。

例如如今你用BeanFactory来“装载”ConfigurableListableBeanFactory的实例:

BeanFactory ioc = new ConfigurableListableBeanFactory();

这个时候对你来讲,这个BeanFactory就是一个装饰器或外观,若是BeanFactory接口不发生改变,你所能用的功能仅仅是BeanFactory提供的几个接口方法。即便可能有人在以后的任什么时候间修改增长了ConfigurableListableBeanFactory的方法。此时尽管ConfigurableListableBeanFactory这个实现类的本质发生了改变,可是对于BeanFactory的使用位置来讲一切照旧,他经过 BeanFactory这个外观装饰接口看到的效果和以前如出一辙。 而扩展了接口以后的实现类,新的代码能够用新的接口。例如:

ConfigurableListableBeanFactory ioc = new ConfigurableListableBeanFactory();

而后咱们还能够继续向下扩展接口和功能。

若是你看过源码,你会发现spring beans的BeanFactory代码最先的编写时间停留在2001年4月13号,距今已经很长的历史了。相信以后确定不断演进扩展了大量的功能。而经过接口派生的实现外观的方式,让古老的代码和后续的新功能友好的共存。对于咱们本身的设计系统或实现“代码级别的迭代”这是一个极好的例子——仅维护一个实现,经过增长外观或装饰器来演进功能,使用者一直都是看到的外观。虽然这样作彷佛会违背类的单一职责的原则。

在接下来介绍ApplicationContext以前先要说明,咱们如今建立一个Spring应该不使用任何BeanFactory相关的接口了,关于这一点官方文档有明确的说明。除了在少数对内存大小有严苛要求的受限制的设备上进行嵌入式开发,其余时候都应该使用ApplicationContext。ApplicationContext实现了BeanFactory的全部功能,并对应用开发提供了不少有用的扩展。BeanFactory如今存在的主要做用是为一些历史第三方库提供支持,如今对于大多数使用Spring的用户来讲他是一个历史性的接口。

ApplicationContext

不知作别人在学习编程开发的早年看到Context这个词是什么感受,反正我是蒙逼了好久。也不知道这词最先是哪位哥翻译的,译成“上下文”?!英文里con-前缀表示汇集、集合吗,context的字面意思明明就是一堆数据的集合吧。其实码界相似让人翻译的翻译还真很多,handle=句柄(deal with,处理器)、socket=套接字(就使用原意插座还好理解)。更狠的是Robustness,真不知道在哪年是哪位大爷出于什么缘由把他翻成“鲁棒性”的。

回到正题,我真正理解Context是在开始了解设计模式以后。在设计模式中Context的概念出如今“策略模式”,该模式的标准解释是执行一个方法会根据当前的状态和对象执行不一样的“策略”,“策略”由于实现类的性质不一样而发生改变。实际上就是用一个Context对“策略”进行包装,而“策略”能够根据须要调整(细节请度娘)。我直接用Spring的ApplicationContext来讲明。

  

(图片来源于网络,若有侵权请告知)

ApplictionContext的继承思路和BeanFactory相似,就再也不介绍了。在核心包中,Spring提供的ApplicationContext实现类目前有FileSystemXmlApplication和ClassPathXmlApplicationContext(Web包里还有Web环境专用的ApplicationContext)。

FileSystemXmlApplication和ClassPathXmlApplicationContext分别表明了2个不一样的“策略”,在咱们使用的时候在建立ApplicationContext时肯定,而且在运行时也能够调整。

class App implements ApplicationContextAware{
	public static void main() {
        // 初始化为策略1
		ApplicationContext springContext = new ClassPathXmlApplicationContext("myXml.xml");
        // 使用策略1的方法,使用者不用知道实现细节
        System.out.println(springContext.getApplicationName());

        // 修改成策略2
        springContext = new FileSystemXmlApplicationContext("/myProject/myXml.xml");
        // 使用策略2的方法,使用者不用知道实现细节
        System.out.println(springContext.getApplicationName());
	}
}

如上面的代码,咱们能够根据咱们须要指定不一样的“策略”。ClassPath和FIleSystem两个类功能都差很少,最大的区别就是加载文件路径的差别——一个从当前工做目录、一个从整个磁盘路径。理论上策略模式还有一个 Strategy接口来包装策略,Spring直接将Context设定为一个接口,而后经过不一样的实现类整合到了一块儿。从实现上来看策略模式并无什么太神奇的东西,实际上仍是一个接口多个实现类。那么看到这里你确定已经忍不住要吼了:这到底有什么用?不就是建立一个实例给一个接口吗?

实际上策略模式和Context是针对分层应用而设计的,不少设计模式的资料只会说模式是什么,可是不会提到模式的来源和立意。我所知道在设计模式中Context的最先概念是来源是来自这篇论文——Context Object A Design Pattern for Efficient Information Sharing across Multiple System Layers(直译为《上下文对象——多层系统的高效信息共享的设计模式》),它大体的结论是在分层应用系统中(例如MVC——view-controller-service-dao)层之间传递(共享)数据时,将相同适用范围和生命周期的全部数据组合到一个Context中去传递能够大大的提高分层以后开发效率——大概就是反正我全部东西都往里面放,你用得着就用,用不着就算,也不用来和我商量要什么了。

因此Context实际上就是按照适用范围(Scope)而不是应用功能(functionality)划分的一个数据对象。 这样在层与层之间传递数据的时候,不管有多少个接口都传递同一个的Context。

例如Spring全局应用就是ApplicatonContext,把IoC和其余全局操做方法的丢到这个Context中。因此最后咱们看到除了IoC的Bean控制接口(BeanFactory)外,他还提供资源控制接口(ResourcePatternResolver)、国际化接口(MessageSource) 、事件发布管理接口(ApplicationEventPublisher)。这些功能并无直接的联系,可是他们的适用范围都是Applicaton级别的,因此都被整合到了ApplicatonContext中。

再例如在WebApplicationContext中,一次请求相关的全部资源以及相关的接口都会整合RequestContext中,RequestContext用于Servlet到咱们自定义的Controller层传递数据。

ApplicationContext继承了BeanFactory,其核心功能仍是管理IoC以及Bean。前面也提到ApplicationContext还扩展了许多功能。下图来自于官方,表现了2者的功能差别。

Feature BeanFactory ApplicationContext

Bean 初始化与设定

Yes

Yes

BeanPostProcessor注册

No

Yes

BeanFactoryPostProcessor注册

No

Yes

国际化支持

No

Yes

事件发布与注册

No

Yes

后续的文章会继续展开介绍这些功能以及背后设计模式的含义。

相关文章
相关标签/搜索