Spring是目前最优秀的框架之一,本文介绍Spring的总体架构以及特性,然后主要针对Spring中部分组件分析其设计理念和设计模式。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。在Spring框架中,总共有十几个组件,总体架构图如图所示:
Spring采用的是分层架构,Core Spring Container为Spring的核心,实现了基于IoC的bean管理容器。在IoC和AOP基础上,扩展了数据层和Web层。
IoC(Inversion of Control)即控制反转,它是一种设计思想。在传统的Java编程思想中,我们会直接在Java对象内部通过new方法直接创建对象,导致程序对象紧密耦合。而在Spring中,创建对象的权限交由IoC容器处理,当程序需要对象时,通过向IoC容器获取得到对象的引用。总的来说,IoC容器控制了外部资源获取,容器查找及注入依赖对象,对象只是被动的接受依赖对象,所以称之为控制反转。
DI(Dependency Injection)即依赖注入,它指的是在Spring中,不同对象之间的依赖关系由运行时通过容器进行确定,简单地说,就是容器在运行时动态地将依赖关系注入到组件中,向某个对象提供它所需要的其他对象。。依赖注入的使用可以提高组件的重用性。应用程序依赖于IoC容器来提供对象需要的外部资源。
那么IoC和DI两个名词又有什么区别呢?从我的理解来看,它们只是对于Spring采用容器管理Java对象的同一件事不同层面的表示,IoC所阐述的是一种思想,指的是Spring将传统的使用new方法直接创建Java对象改为通过IoC容器获取Java对象,IoC容器控制的对象创建的权利,降低了Java对象之间的依赖关系;DI则大多指得是实现IoC的方式,通过依赖注入实现控制反转。其实DI是2004年大师级人物Martin Fowler针对“控制反转“给出了的新的名字,相对“控制反转“而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Aop(Aspect Oriented Programming)即面向切面编程,它是针对与OOP(Object Oriented Programming)即面向对象编程的补充。”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任。OOP是针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。Aop是针对业务处理过程中的切面进行提取,它所面对的是处理过程的某个步骤或阶段,利用”横切”技术,剖解开封装的对象内部,将影响了多个类的公共行为封装到一个可重用模块(即切面),减少系统的重复代码,降低模块之间的耦合度,有利于未来的可操作性和可维护性。Aop的应用场景有日志记录,性能统计,安全控制,事务处理,异常处理等。
Aop把系统分为核心关注点和横切关注点。核心关注点是业务处理的主要流程,横切关注点是与业务处理流程关系不大的补充其他补充功能。横切关注点的一个特点是经常发生在多个核心关注点上,而且各处处理方式基本相似,比如权限认证、日志、事务。Aop的作用在于分离系统中的核心关注点和横切关注点。
Aop采用了Proxy模式,例如JdkDynamicAopProxy和Cglib2AopProxy,用到了JDK的动态代理模式。
$Proxy是创建的代理对象,Subject是抽象主题,代理对象是通过Invocatio-nHandler来持有对目标对象的引用。除了实现被代理对象的接口外,还会有org.springframework.aop.SpringProxy和org.springframework.aop.fram-ework.Advised两个接口。
在Spring中,Bean类似于java面向对象编程中的Object,Spring把对象包装在Bean中而达到对对象管理以及一些额外操作的目的。Bean组件在Spring的org.springframework.beans包下。Bean 组件主要包括三项功能:Bean定义,Bean创建以及Bean解析。在使用Spring框架时,用户只需对Bean进行定义,对于Bean的创建和解析由Spring负责(对用户是透明的)。
Bean在创建时采用的是工厂模式,类图如图1所示,它的顶级接口是BeanFactory,它是典型工厂方法模式的接口,有三个子接口继承至该接口,分别为ListableBeanFactory、HierarchicalBeanFactory和Autowire-CapableBeanFactory。虽然最终的实现类实现了之前接口中的所有方法,但是对于每一个接口来说,它们都有各自使用的场合,主要是为了区分在Spring 内部对象的传递和转化过程中,对对象的数据访问所做的限制。例如ListableBean-Factory 接口表示这些 Bean 是可列表的,它可以列出工厂可以生产的所有实例;HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean;AutowireCapableBean-Factory 接口定义 Bean 的自动装配规则,根据类定义BeanDefinition装配Bean、执行前、后处理器等。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。
Bean的定义完整地描述了在Spring配置文件中定义的
节点中所有的信息,包括各种子节点。当 Spring 成功解析一个
节点后,在 Spring 的内部它被转化成 BeanDefinition 对象,以后所有的操作都是对这个对象完成的。
Bean 的解析过程非常复杂,功能被分的很细,因为需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。
Context 组件源代码位于 Spring 的 org.springframework.context 包下,Context 组件在 Spring 中的实际上就是给 Spring 提供一个运行时的环境,用以保存各个对象的状态。
ApplicationContext 是 Context 的顶级父类,它除了能标识一个应用环境的基本信息外,他还继承了五个接口,这五个接口主要是扩展了 Context 的功能。ApplicationContext继承了BeanFactory,说明了Spring容器中运行的主体对象是Bean,另外ApplicationContext继承了ResourceLoader接口,使得ApplicationContext可以访问到任何外部资源。
ApplicationContext的子类主要包含两个:
ConfigurableApplicationContext表示该种类型的Context是可修改的,也就是在构建Context时用户可以动态添加或修改已有的配置信息,它又有多个子类,其中最经常使用的是可更新的Context,即
AbstractRefreshableApplicationContext类。
WebApplicationContext是为web准备的Context,它可以直接访问到ServletContext,通常情况下,这个接口使用的少。
再往下分就是按照构建Context的文件类型,接着就是访问Context的方式。这样一级一级构成了完整的Context等级层次。
总体来说ApplicationContext必须要完成以下几件事:
Context作为Spring的IoC容器,基本上整合了Spring的大部分功能,或者说是大部分功能的基础。
Core组件一个重要组成部分就是定义了资源的访问方式,把资源都抽象成一个接口,本节内容主要介绍该部分内容。
Resource接口封装了各种可能的资源类型,对使用者屏蔽了文件类型的不同。Resource接口继承了InputStreamSource接口,接口中的getInput-Stream方法,返回的是InputStream类。这样所有的资源都被可以通过InputStream这个类来获取,所以屏蔽了资源的提供者对文件类型不同的感受。另外还有一个问题就是加载资源的问题,也就是资源的加载者要统一,在Spring中这个任务是由ResourceLoader接口完成,它屏蔽了所有的资源加载者的差异,只需要实现这个接口就可以加载所有的资源,它的默认实现是DefaultResourceLoader。