设计模式之spring分析
Spring已经在java的世界里横行很多年了,但是阅读起来并不那么容易。特别是接口概念的广泛使用,更增加了分析的难度,本文从设计模式的角度来对其进行分析,会忽略实现的具体细节。本文中,对于spring所涉及到的模式,并非来自官方,可能某些地方会让读者感到牵强,纯属个人见解,希望读者批判阅读。
我们将从讨论BeanFactory和ApplicationContext的关系开始叩开spring的设计之门(实际上是AbstractApplicationContext和DefaultListableBeanFactory的关系)。简言之,BeanFactory的核心作用就是创建bean,ApplicationContext的核心作用是创建BeanFactory并为我们提供统一的访问接口。如图我们来看一下他们的类图关系。
这里省略了其他辅助接口,只留下二者的关系,以便于我们分析。我们可以这样描述一下AbstractApplicationContext的作用:AbstractApplicationContext实际上是在客户端和DefaultListableBeanFactory之间起到了中介的作用,也就是我们不能直接访问BeanFactory,而是要通过ApplicationContext来访问。这样就很明了了,代理模式的意图正是如此。明确了BeanFactory和ApplicationContext之间的关系有助于我们在总体上把控框架的结构,不至于让太多的接口搞的眼花缭乱。
上文提到了,ApplicationContext的一个重要作用就是创建BeanFactory。BeanFactory的构建过程对我们来说是透明的,那么我们有没有什么办法扩展BeanFactory的行为么?这时候就涉及到BeanFactoryPostProcessor接口了。这个接口的作用是丰富,扩展BeanFactory功能。
根据上图,这是一种设计模式么?下图是我在网络上找到了一个观察者模式的url图
我们是否可以描述一下上图的含义呢?多个BeanFactoryPostProcessor同时在观察着DefaultListableBeanFactory的构建,一旦构建完成,就发送给所有的观察者来丰富其功能。从这个思路来看这个是观察者无疑了。我们在来看看责任链模式的结构图。
责任链的一个主要特征是:子类间构成一个链表结构。既然是链表,我们可以稍微改进一下,将链表改成数组。如果链表中的所有元素都执行。那么责任链模式就便形成了如下结构
从这个角度来看BeanFactoryPostProcessor结构,更像是责任链模式。那么他到底属于哪种结构呢?从类图上来分析,他更倾向于观察者模式,但是意图并不一致,观察者的意图是:当事件发生时,子类去更新各自的行为。比如下文要讲到的ApplicationListener接口,但是这里的意图是丰富BeanFactory行为。如果从意图上分析,更像是责任链模式。在一个链式结构中逐一丰富BeanFactory行为。只不过这里把链表结构改成了数组结构。所以这里的结论是:不知道。可能是观察者,可能是责任链,也可能合并了二者,更有可能压根什么都不是。具体读者自行定论。BeanPostProcessor接口也是以同样的结构来丰富修改具体bean的构建过程。
好了,现在bean工厂构建起来了。在创建xml中定义的bean对象前,BeanFactory第一个要做的事儿就是把xml中的各个标签解析成BeanFactory能够识别的BeanDefinition。
第一个问题:我们将以怎样的方式来加载我们的xml文件呢?更确切的,我们的xml可能是本地的一个文件,也可能是在远程下载的,还有可能已经存在于二进制内存中了。对于这些可能的情况,我们该怎样抽象?进而怎样加载到程序中?spring的做法是将这些可能的方式统一抽象为Resource接口,定义ResourceLoader接口专门来加载Resource。他们的关系如下图:
看出来了么?没错,spring用工厂方法设计模式将xml文件载入内存。当我们new一个ClassPathXmlApplicationContext开始使用spring的时候,实际上是选择了加载方式,进而选择了对应的资源模式。
第二个问题,数据已经加载到内存中了,我们接下来的目标自然是对xml文件进行解析。如果你稍微有点spring使用经验,就知道xml中除了<bean>标签还有其他各种各样的标签,比如事务的,aop等等,有的读者可能还想自定义满足标签。这怎么办?问题总是接踵而来,我们来看一下spring的处理方式,如下图
对于xml中不同的命名空间,spring用策略模式提供了完美的解决方案。如果你有兴趣的话可以画一下BeanDefinitionParse接口的结构图。你会发现,他还是一个策略模式。需要注意的是,spring会自动扫描类路径META-INF/spring.handlers配置文件来寻找相关策略实现类。
至此,spring可以完全解析xml文件了。接下来就可以大胆的建造我们配置的bean了。上文提到了,如果我们想要丰富,扩展,改变bean的构建过程。可以使用BeanPostProcessor接口。典型的AOP,代理,事务都是通过这个接口进行扩展的。我们的扩展点也在这里。他的结构请参考BeanFactoryPostProcessor结构。
Bean创建完成后,spring这个超大工厂加工工作基本完成了。这时候他会发送一个事件,通知关心相关接口。结构图如下
没有任何悬念,这个是观察者模式的典型应用。
这里还要点到两个设计模式,一个是模板方法。毫无疑问,spring的这种层层继承结构大量的使用的模板方法。另一个是门面模式,如图
ApplicationContext把大量辅助接口统一在一起,为我们提供了统一门面。
分析到此为止了。设计模式是我们学习各种框架的重要工具。识别是是哪种设计模式大体需要两步,第一看“面相”,即类图结构是否相似,第二看“心里”,即意图是否吻合。还是那句话,主要的不是我们看出了是哪种设计模式,最为重要的是我们在分析中的思维过程,在分析中学到的设计模式的具体使用方式以及对于对于不同问题的抽象过程。
java企业级通用权限安全框架源码 SpringMVC mybatis or hibernate+ehcache shiro druid bootstrap HTML5