Spring的IOC和AOP
Spring的简单理解
Spring技术可以说是java企业开发里最重要的技术,不过真的理解Spring的作用和意义还真是一件麻烦的事情。
Spring最根本的使命:简化Java开发。
为了降低Java开发的复杂性,Spring采取以下4种关键策略:
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模版减少样板示代码
很多人对Spring理解其实都是停留在使用阶段(例如:声明式事务很好用等等),当今的Spring技术生态环境里可谓是蔚为壮观,Spring已经包罗万象,它的内容之多完全不亚于它的本源Java语言了,而Spring这么大的框都是建立在IOC和AOP技术之上,只有深入理解了这两个技术我们才能明白为什么Spring这个框能装的下那么多东西了。在理解IOC和AOP之前,可以先看一下Spring给我们带来了哪些好处。
Spring的优点
- 轻量级:相较于EJB容器,Spring采用的IoC容器非常的轻量级,基础版本的Spring框架大约只有2MB。Spring可以让开发者们仅仅使用POJO(Plain Old Java Object,相对于EJB)就能够开发出企业级的应用。这样做的好处是,你不需要使用臃肿庞大的 EJB容器(应用服务器),你只需要轻量的servlet容器(如Tomcat)。尤其在一些开发当中,很稀缺内存和CPU资源时,采用Spring比EJB无论是开发还是部署应用都更节约资源。
- 控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
- 面向切面编程(AOP): Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
- MVC框架:Spring MVC是一个非常好的MVC框架,可以替换其他web框架诸如Struts。
- 集成性:Spring非常容易和其他的流行框架一起集成开发,这些框架包括:ORM框架,logging框架,JEE, Quartz,以及Struts等表现层框架。
- 事务管理:Spring强大的事务管理功能,能够处理本地事务(一个数据库)或是全局事务(多个数据,采用JTA)。
- 模块分离:Spring框架是由模块构成的。虽然已经有太多的包和类了,但它们都按照模块分好类了,你只需要考虑你会用到的模块,而不用理其他的模块。
- 异常处理:由于Java的JDBC,Hibernate等API中有很多方法抛出的是checked exception,而很多开发者并不能很好的处理异常。Spring提供了统一的API将这些checked exception的异常转换成Spring的unchecked exception。
- 单元测试:Spring写出来的代码非常容易做单元测试,可以采用依赖注射(Dependency Injection)将测试的数据注射到程序中。
Spring的IOC
IOC技术第一个解释叫做控制反转(IOC),它还有个解释就是依赖注入(DI),这两个名字很难从字面理解,但是当你理解它的原理后就会发现它们的描述是何等准确。IOC技术的本质就是构建对象的技术换句话说就是将一个类实例化成对象的技术。
耦合具有两面性。一方面,紧密耦合的代码难以测试,难以复用,难以理解,并且表现出“打地鼠”式的bug特性(修复一个bug,导致出现一个新的或者甚至更多的bug)。另一方面,一定程度的耦合又是必须的,完全没有耦合的代码什么也做不了。为了完成有实际意义的工作,不同的类必须以适当的方式进行交互。总而言之,耦合是必须的,但应当小心谨慎的管理它。通过控制反转或者依赖注入,对象的依赖关系将由负责协调系统中各个对象的第三方组件在创建对象时设定。对象无需自行创建或管理它们的依赖关系,依赖关系将被自动注入到需要它们的对象中去。
我们通过实际生活中的一个例子来解释一下IOC:
例如我们有个roo对象作用是完成打猎的操作,那么打猎这个对象内部包含两个辅助对象:人和枪,只有人和枪赋予了打猎这个对象,那么打猎对象才能完成打猎的操作,但是构建一个人和枪的对象并不是看起来那么简单,这里以枪为例,要创造一把枪我们需要金属,需要机床,需要子弹,而机床和子弹又是两个新对象,这些对象一个个相互嵌套相互关联,大伙试想下如果我们在java代码里构建一个枪的对象那是何其的复杂,假如我们要构造的不是简单的枪对象而是更加复杂的航空母舰,那么构造这个对象的成本之高是让人难以想象的,怎么来消除这种对象相互嵌套相互依赖的关系了?
Spring提供了一种方式,这种方式就是Spring提供一个容器,我们在xml文件里定义各个对象的依赖关系,由容器完成对象的构建,当我们Java代码里需要使用某个实例的时候就可以从容器里获取,那么对象的构建操作就被Spring容器接管,所以它被称为控制反转。
控制反转的意思就是本来属于java程序里构建对象的功能交由容器接管,依赖注入就是当程序要使用某个对象时候,容器会把它注入到程序里。在Java开发里我们想使用某个类提供的功能,有两种方式:一种就是构造一个新的类,新的类继承该类,另一种方式则是将某个类定义在新类里,那么两个类之间就建立一种关联关系,Spring的IOC容器就是实现了这种关联关系。
通过上面这段内容,相信大家应该会对IOC有个比较清晰的了解了。关于Spring中IOC部分是如何实现以及使用,就不进行讨论了,本文的目的也是能从整体上把握一下。但可以稍微提一点,Spring的IOC功能其实就是依赖于Java的反射机制。直白点说,当你在xml文件中配置好了bean(bean需要提供全类名)之后,Spring通过自己的类对xml文件进行解析,然后利用反射机制将对象创建出来,然后放到自己的数据结构中,比如Map。然后键就是bean中的id属性的值,值就是创建的对象。
Spring的AOP
在设计模式里有一种代理模式,代理模式将继承模式和关联模式结合在一起使用,代理模式就是继承模式和关联模式的综合体,不过这个综合体的作用倒不是解决对象注入的问题,而是为具体操作对象找到一个保姆或者是秘书,这就和小说里的二号首长一样,这个二号首长对外代表了具体的实例对象,实例对象的入口和出口都是通过这个二号首长,具体的实例对象是一号首长,一号首长是要干大事的,所以一些事务性,重复性的工作例如泡茶,安排车子,这样的工作是不用劳烦一号首长的大驾,而是二号首长帮忙解决的,这就是AOP的思想。AOP解决程序开发里事务性,和核心业务无关的问题,但这些问题对于业务场景的实现是很有必要的,在实际开发里AOP也是节省代码的一种方式。
AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
Spring的AOP代理对象的生成
Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。