Spring的IOC与AOP特性

Spring的IOC特性


一. 什么是控制反转


图1. 控制反转

见图1,软件中的对象就如同图中的齿轮,协同工作,互相耦合,若是一个零件不能正常工作,则会导致整个系统的奔溃,这就是强耦合系统。为了解决对象间耦合度过高的问题,软件专家Michael Mattson提出了IoC理论。

控制反转(Inversion of Control)是一种面向对象编程中的一种设计原则,用来解决计算机代码之间的耦合度。其基本思想是:借助于"第三方"实现具有依赖关系的对象之间的耦合。

图2. IoC

见图2,由于引进了IoC容器,使得A、B、C、D这四个对象没有了耦合关系,对象的控制权全部由IoC容器负责。

我们再次来对比一下:

  1. 软件系统在没有引入IoC容器之前,如图1,对象A依赖与对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
  2. 软件系统在引入IoC容器之后,就完全不同了。如图2,由于IoC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要B的对象,IoC容器会主动创建一个对象B注入到对象A需要的地方。

通过对比,可以看出对象A依赖对象B的过程,由主动行为变成了被动行为,控制权颠倒了过来,这就是"控制反转"的由来。

二. 什么是依赖注入


当A对象需要调用B对象方法时,这种情况在Spring中称为依赖,即A对象依赖B对象,Spring把互相调用的关系称为依赖关系。

在传统模式下当需要调用其他对象的方法时,一般有以下两种方式:

  • 原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
  • 简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。

对于第一种方式,由于调用者需要通过形如"new 被依赖对象构造器();"的代码来创建对象,这种方式会导致调用者与被依赖对象实现类的硬编码耦合,不利于项目升级维护。

对于第二种方式,要把握一下三点:

  • 调用者面向被依赖对象的接口编程
  • 将被依赖对象的创建交给工厂完成
  • 调用者通过工厂来获得被依赖组件

这样,调用者只需与被依赖对象的接口耦合,这样就避免了类层次的硬编码耦合。缺点是,调用组件需要主动通过工厂去获取被依赖对象,这就会带来调用组件与被依赖对象的耦合。

当使用Spring容器后,程序无须使用new调用构造器去创建对象,所有的Java对象都可交给Spring容器去创建;当调用者需要被依赖对象的方法时,调用者无须主动获取被依赖对象,只需要等待Spring容器注入即可。

三. 控制反转与依赖注入的关系


  • 控制反转是一种思想
  • 依赖注入是一种设计模式

IoC框架使用依赖注入作为实现控制反转的方式,但是控制反转还有其他的实现方式,例如说ServiceLocator,所以不能将控制反转和依赖注入等同。

参考资料


Spring的AOP特性


以下内容来自于博客Spring AOP 实现原理与 CGLIB 应用

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP实现的关键就在于AOP框架自动创建的AOP代理,AOP代理则可分为静态代理和动态代理两大类,其中静态代理是指AOP框架提供的命令进行编译,从而在编译阶段就可生成AOP代理类,因此也被称为编译时增强;而动态代理则是在运行时借助于JDK动态代理、CGLIB等在内存中“临时”生成AOP动态代理类,因此也被称为运行时增强。

一. AOP的存在价值


在传统的OOP编程里以对象为核心,整个软件系统由一系列相互依赖的对象组成,而这些对象将被抽象成一个个类,并允许使用类继承来管理类与类之间一般到特殊的关系。随着软件规模的增大,应用的逐渐升级,慢慢出现了一些OOP很难解决的问题。

我们可以通过分析、抽象出一系列具有一定属性与行为的对象,并通过这些对象的协作来形成一个完整的软件功能。由于对象可以继承,因此我们可以把具有相同功能或相同特性的属性抽象到一个层次分明的类结构体系中。随着软件规范的不断扩大,专业化分工越来越系列,以及OOP应用实践的不断增多,随之也暴露出了一些OOP无法很好解决的问题。

现在假设系统中有3段完全相似的代码,这些代码通常会采用“复制”、“粘贴”方式来完成,通过这种“复制”、“粘贴”方式开发出来的软件如图1所示。


图1. 多个地方包含相同代码的软件

看到如图1所示的示意图,可以看到了这种设计的不足之处。当有一天,图1中的深色代码段需要修改,那是不是要打开3个地方的代码进行修改?如果不是3个地方包含这段代码,而是100个地方,甚至是1000个地方包含这段代码段,那会是什么后果?

为了解决这个问题,我们通常会采用将如图1所示的深色代码部分定义成一个方法,然后在3个代码段中分别调用该方法即可。在这种方式下,软件系统的结构如图2所示。


图2. 通过方法调用实现系统功能

对于如图2所示的软件系统,如果需要修改深色部分的代码,只要修改一个地方即可,不管整个系统中有多少方法调用了该方法,程序无须修改这些地方,只需要修改被调用的方法即可——通过这种方式,大大降低了软件后期维护的复杂度。

对于如图2所示的方法1、方法2、方法3依然需要显式调用深色方法,这样做能够解决大部分应用场景。但对于一些更特殊的情况:应用需要方法1、方法2、方法3彻底与深色方法分离——方法1、方法2、方法3无须直接调用深色方法,该如何解决?

因为软件系统需求变更是非常频繁的事情,系统前期设计方法1、方法2、方法3时只实现了核心业务功能,过了一段时间,我们需要为方法1、方法2、方法3都增加事务控制;又过了一段时间,客户提出方法1、方法2、方法3需要进行用户合法性验证。只有合法的用户才能执行这些方法。因此,我们希望有一种特殊的方法:我们只要定义该方法,无须在方法1、方法2、方法3中显式调用它,系统会“自动”执行该特殊方法。

实现上述需求的技术就是AOP。AOP专门用于处理系统中分布于各个模块(不同方法)中交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP已经成为一种非常常用的解决方案。

二. Spring AOP原理剖析

Spring AOP框架对AOP代理类的处理原则是:如果目标对象的实现类实现了接口,Spring AOP将会采用JDK动态代理来生成AOP代理类;如果目标对象的实现类没有实现接口,Spring AOP将会采用CGLIB来生成AOP代理类——不过这个选择过程对开发者完全透明、开发者无须关心。

AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用。AOP代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。

AOP代理所包含的方法与目标对象的方法示意图如图3所示。


图3. AOP代理的方法与目标对象的方法

Spring的AOP代理有Spring的IoC容器负责生成、管理,其依赖关系也有IoC容器负责管理。因此,AOP代理可以直接使用容器中的其他Bean实例作为目标,这种关系可由IoC容器的依赖注入提供。

纵观AOP编程,其中需要程序员参与的只有3个部分:

  • 定义普通业务组件
  • 定义切入点,一个切入点可能横切多个业务组件
  • 定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

上面3个部分的第一个部分是最平常不过的事情,无须额外说明。那么进行AOP编程的关键就是定义切入点和定义增强处理。一但定义了合适的切入点和增强处理,AOP框架将会自动生成AOP代理,而AOP代理的方法大致有如下公式:

代理对象的方法 = 增强处理 + 被代理对象的方法

Spring AOP的实现原理:AOP框架负责动态生成AOP代理类,这个代理类的方法则由Advice和回调方法对象的方法所组成。

对于前面提到的图2所示的软件调用结构:当方法1、方法2、方法3......都需要去调用某个具有“横切”性质的方法时,传统的做法是程序员去手动修改方法1、方法2、方法3......通过代码来调用这个具有“横切”性质的方法,但这种做法的可扩展性不好,因为每次都要修改代码。

于是AOP框架出现,AOP框架则可以“动态的”生成一个新的代理类,而这个代理类所包含的方法1、方法2、方法3的代码,程序员只要定义切入点即可——AOP框架所生成的AOP代理类中包含了新的方法1、方法2、方法3,而AOP框架会根据切入点来决定是否要在方法1、方法2、方法3中回调具有“横切”性质的方法。

简而言之:AOP原理的奥妙就在于动态地生成了代理类,这个代理类实现了图2的调用——这种调用无须程序员修改代码。

参考资料


  • 《轻量级JavaEE企业应用实战》(第4版)李刚 编著
  • 《疯狂Java讲义》李刚 编著
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容