第一日,上帝说要有光,于是有了光;
第二日,上帝说要有水和空气,于是有了水和空气;
第三日,上帝说要有植物,于是有了植物;
第四日,上帝说要有日月星辰,于是有了日月星辰;
第五日,上帝说要有鱼和鸟,于是有了鱼和鸟;
第六日,上帝说要有飞虫走兽和人,于是有了飞虫走兽和人;
第七日,上帝说累了,于是休息。
从上帝造人可以看出来,上帝非常聪明,他没有在无任何基础的第一天先造人……上帝造人尚且需要七天,我们学习spring的骨架设计也得至少7天。
第一天:
在java届,有位名叫Rod Johnson的牛人,发现最初的java企业级开发处于混沌状态。
于是,它决心编写一个能够解决问题的通用的基础架构。
因为它深信面向接口编程能够将变化控制到最小,同时也利于扩展和变化。于是,它编写了如下的接口。
在混沌状态最先要创造的是一切对象的母亲BeanFactory,有了它,就能够得到一切它孕育的对象和属性,也就是说首先要造盖亚--大地之母。
有了最初的母亲BeanFactory,johnson想,如果我要得到一组Bean对象而不单单是某个或某几个呢?另外,如果母亲的孩子也要孕育对象呢?于是,johnson创造了ListableBeanFactory以操作一组bean对象,比如getBeansOfType就能够根据得到同类型的一组Bean;创造了HierarchicalBeanFactory来解决多个BeanFactory的层次问题,比如getParentBeanFactory就能够得到BeanFactory的父Factory。
这个BeanFactory最终是要在某个应用上使用的,那么,需要给予BeanFactory在一个应用中活动的能力。在BeanFactory中,只需要考虑跟bean相关的行为,比如怎么得到bean,bean的类型等;而如果要赋予其在应用中的能力,则就需要考虑更多,比如应用的名字,启动时间,id等等跟应用本身相关的行为和属性,于是johnson想到了创造ApplicationContext。johnson想,这个ApplicationContext一定要能做许多事,要能够处理参数化和国际化的文本信息,于是增加了MessageSource接口;要能发布事件以便解耦组件,于是有了ApplicationEventPublisher接口;要能得到资源文件,于是有了ResourcePatternResolver接口;要能有在不同环境有不同处理对象的能力,于是有了EnvironmentCapable接口。
ApplicationContext继承了所有这些接口。
但是最重要的是,无论是BeanFactory还是ApplicationContext,它们都需要有可配置的能力,于是有了子接口ConfigurableBeanFactory和ConfigurableApplicationContext;另外,web在当时是非常重要的趋势,而且相比其他应用有些独特,需要得到ServletContext,于是有了WebApplicationContext。
到目前为止,johnson都是面向接口进行行为的抽象思考,并未具体实现他们。
看着创造出来的BeanFactory和ApplicationContext,johnson意识到这一天的工作远远没有结束,因为并没有真正解决怎么能够让整套体系运转起来,于是,johnson开始思索如何实现他们。
johoson首先想到的还是这个实现应该具备什么能力?当然要把之前提到的AutowireCapableBeanFactory,ListableBeanFactory和ConfigurableBeanFactory都包括进去。因此创造了ConfigurableListableBeanFactory。其次,需要考虑对于bean对象的几种能力,一是起别名的能力;二是保存单例对象的能力;三是缓存的能力;他们分别在SimpleAliasRegistry类,DefaultSingletonBeanRegistry类和FactoryBeanRegistrySupport类中实现。
最终,创造出了DefaultListableBeanFactory,它是spring中一切ioc工厂的原型,是BeanFactory第一个真正的孩子,这个孩子非常重要,已经成为独立的创建ioc容器的基础,如果有扩展和使用,大多是继承它或者组合使用它。
如果要初始化一个DefaultListableBeanFactory,可以用如下代码
ClassPathResource res = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory f = new DefaultListableBeanFactory();
XmlBeanDefinitionReader r = new XmlBeanDefinitionReader(f);
r.loadBeanDefinitions(res);
接下来johnson想,BeanFactory有了一个功能比较全面的默认实现,那么ApplicationContext呢?于是johnson孜孜不倦的创造了3个重要的ApplicationContext实现:FileSystemXmlApplicationContext, ClassPathXmlApplicationContext, AnnotationConfigWebApplicationContext(其实还有很多,比如处理portlet的, 处理web的)
johnson最先考虑的是如何去做spring的启动流程,它应该放到一个比较抽象的层次以便下层的所有类能够复用。于是他用一个AbstractApplicationContext实现了ConfigurableApplicationContext。还有一个很重要的功能,即将一个文件以资源的形式加载进来,这需要将资源抽象为Resource类,将定位资源的具体实现抽象到ResourceLoader,AbstractApplicationContext同样需要继承DefaultResourceLoader以提供这个功能。AbstractApplicationContext完成了整个启动流程(上帝将它安排在第二天完成),唯独没有做对BeanFactory的管理。于是,它的子类AbstractRefreshableApplicationContext专门做了这件事,实现了refreshBeanFactory, closeBeanFactory, getBeanFactory专门对BeanFactory的生命周期做了一些管理,但是AbstractRefreshableApplicationContext仍然没有加载所有配置好的Bean。到哪里加载配置好的资源,实际上到了下层的子类去做,比如FileSystemXmlApplicationContext,就是到文件系统去读一个xml形式的applicationContext;ClassPathXmlApplicationContext则是到类加载路径下去读这个applicationContext。而AnnotationConfigWebApplicationContext则从类文件的annotation中加载bean,spring的扫描也从此开始。
看着主要的框架已经建立起来,johnson满意的笑着睡着了。