Spring 揭秘之一起来看AOP

一起来看AOP

软件开发一直在寻找更高效、更容易维护甚至更容易扩展的方式;为了提高开发效率,我们对语言进行抽象,从而有了高级程序设计语言;为了便于维护和扩展,我们冲出“原始部落”,走过面向过程编程,到达面向对象编程;但是,不过走过的路多长,我们一直在寻找更完美、更高效的软件开发方式;

面向对象并不是那颗能搞定一切的“银弹”。软件开发的目的,最终在于解决各种需求,包括业务需求和系统需求;使用面向对象方法,可以对业务需求等进行很好的封装和实现,但是对系统需求来说,情况却不一样;

对于业务需求来说,其实现和需求基本上是一对一的关系,无论是从开发还是维护的角度来看,都比较方便;(通常是这样吧,或者说一对很少?)

对于系统需求,如日志记录、安全检查等来说,其实现和需求是一种多对一的关系:类似的功能遍布所有的业务对象;

OOP擅长实现业务需求,但是对于系统需求来说,却没有好的解决方法;面对OOP无法满足我们对提高效率、便于维护和扩展的终极追求时,我们有两种做法,一是替代它,二是增强它;到目前为止,还没有可以替代OOP方法,好在我们找到了第二种方法:AOP;

前面提到,系统需求的一大特点就是相同的的功能实现,分布广泛;以AOP的行话来说,这些广泛分布的点称为横切关注点;于是,我们需要一种方法对这些横切关注点进行组织和实现,这就有了Aspect的概念,我们通过Aspect来封装横切关注点;

Aspect之对于AOP,相当于Class之对于OOP。

我们前面也提到,AOP是对OOP的增强,当AOP和OOP携手共进时,我们就可以开心地构建系统,解决需求啦;

AOP的尴尬

AOP关注于系统需求,而OOP则关注业务需求;但是AOP却不能独立存在,因为没有任何业务功能的系统,毫无存在的必要,自然也就没有AOP了;所以,AOP的实现必须“寄生”于OOP的领土之中;

AOP走向现实

OOP是一种构建程序的理念;AOP也是;它们都有一些基本的概念,都需要编程语言提供对其概念的支持;类、对象如此;Join Point、Aspect也是如此;我们把对AOP提供支持的语言,称为AOL(Aspect Oriented Language)

用于系统实现的语言通常称为寄生语言;而将AOP组件集成到OOP组件的过程,用AOP的术语来说叫做织入;不同的AOL对织入有不同实现,这也可以理解;但是不管该过程如何简单或者复杂,它都是由AOL进行处理的,我们只需要专注于系统需求和业务需求就好;

静态AOP时代

静态AOP,第一代AOP,以AspectJ为代表;通过特定编译器将Aspect织入系统的静态类中;优点是,Aspect以字节码的形式编译到Java类中,对虚拟机不会造成什么运行时的性能损耗;缺点就是灵活性差,改变AOP内容时,需要重新编译Aspect并织入到系统中;

动态AOP时代

动态AOP,又称第二代AOP。大多使用Java提供的动态特性实现Aspect的织入过程;AspectJ也提供了动态AOP实现;其和静态AOP最大的区别在于,动态AOP的织入过程是在系统开始运行之后进行的,而不是在编译阶段进行;好处就是可以动态修改AOP的织入信息,而不需要变更其他系统模块;缺点就是不可避免的带来性能上的损耗;

但是随着JVM的升级,对反射和字节码操作技术的更好支持,性能损失会逐渐降低而变得可以接受;

Java平台上的AOP实现机制

动态代理

将横切关注点的逻辑封装到动态代理的InvocationHandler中,然后在系统运行期间,根据横切关注点需要织入的位置,将横切逻辑织入到相应的代理类中;

缺点是需要织入横切逻辑的模块类必须实现相应的接口,因为动态代理只对接口有效;

Spring AOP默认情况下就是采用这种机制实现AOP;

动态字节码增强

Java虚拟机加载的class文件有其规范,所有遵循该规范的class文件均可由Java虚拟机处理执行;所谓动态字节码增强就是说通过CGLIB等Java库,在程序运行期间,动态构建字节码文件,为需要横切逻辑的类生成子类,并将横切逻辑加入其中;这时,应用程序执行期间使用的不再是原来的业务类,而是动态生成的子类,从而达到将横切逻辑织入系统的目的;

Spring AOP在无法使用动态代理进行AOP功能扩展时,就会采用CGLIB库的动态字节码增强来支持AOP的功能扩展;

Java代码生成

这种方式很古老,已经退休了——生成代码后还得编译,不是吗?

自定义类加载器

自定义类加载其通过读取外部文件所规定的织入规则和必要信息,在加载class文件的时候将横切逻辑添加到系统模块类中,然后将改动后的class文件交给Java虚拟机即可;功能很强大,但是有时候类加载体系会被应用服务器所控制,使用场景受到限制;

AOL扩展

最为强大,也最难以掌握的一种方式;强大在于其AOP的逻辑体系是完整的,所有概念都能得到最完美的表达;同时具有强类型检测,对横切关注点要切入的系统有更全面的控制;当然,对运行时性能、Java虚拟机也不会有额外的负担;

代价就是,需要重新学习一门扩展了已有语言的AOL或者全新的AOL。

请注意KISS原则:Keep It Simple and Stupid。

AOP国家的公民

AOP术语本就不统一,所以接下来只会给出英文原意;

Joinpoint

AOP功能模块和OOP功能模块相互结合的地方;也就是进行织入的地方。进行织入操作的系统执行点称为Joinpoint。

常见的Joinpoint类型有:

  1. Method Call:方法调用点;
  2. Method Call Execution:方法执行点;
  3. Constructor Call:构造方法调用点;
  4. Field Set:字段设置点;
  5. Field Get:字段获取点;
  6. Exception Handler Execution:异常处理执行点;
  7. Class Initialization:类初始化点;

Pointcut

描述了一组Joinpoint。在将横切逻辑织入当前系统的过程中,根据Pointcut的描述来确认Joinpoint,这样才能知道往哪些Joinpoint织入横切逻辑;

Pointcut的表达方式
  1. 直接指定Joinpoint所在方法的名称:适合用于Joinpoint较少且简单的情况;当然,仅限于支持方法级别;
  2. 正则表达式:充分利用正则表达式强大的描述能力来指定多个Joinpoint。几乎所有的AOP产品都支持这种方法;
  3. 使用特定的Pointcut表述语言:最为强大、灵活性最好,但是实现起来就很复杂;需要设计语法、实现解释器等;AspectJ使用这种方式来描述Pointcut,和正则表达式很类似;Spring 支持AspectJ的Pointcut表述语言;
Pointcut运算

Pointcut描述了一组Joinpoint,所以算是一种集合,于是便可以进行一些集合运算;运算结果也是Pointcut;

Spring配置文件中使用and、or等单词作为逻辑运算符,AspectJ使用&&、||等;

Advice

横切逻辑的载体;它将被织入到Joinpoint中;Joinpoint描述了执行点,代表着一个动作;在执行点上执行的内容就是Advice啦;而根据Advice所表示动作的执行时机,可以将其分为:

  1. Before Advice:在Joinpoin指定位置之前执行的Advice;
  2. After Advice:在Joinpoint指定位置之后执行的Advice;可进一步分为:
    1. After Returning Advice:Joinpoint 处的流程正常返回后,执行的Advice;
    2. After Throwing Advice:只有Joinpoint执行的过程中抛出异常时,才会执行的Advice;
    3. After Advice:类似Finally代码块,不管如何,都会执行;
  3. Around Advice:也被AOP Alliance属下的AOP实现称为拦截器;其对Joinpoint进行包裹;J2EE中的Filter,实际上就是一种Around Advice;
  4. Introduction:它可以为原有的对象添加新的特性或者行为;在Spring AOP中会介绍;

Aspect

Aspect对系统中的横切关注点逻辑以及横切关注点进行封装;一般来说,Aspect包含多个Pointcut和相对应Advice;

织入和织入器

不同AOP的实现,有不同的织入器和植入方式;它们都有相同的职责:将横切关注点逻辑织入系统;

目标对象

符合Pointcut所描述的条件,即将在织入过程中被织入进行横切逻辑的对象;

小结

AOP作为对OOP的一种补充,帮助OOP解决了对散落到系统各处的相同功能的管理;AOP涉及到很多新的概念,所以再开始Spring AOP的介绍之前,首先对AOP的基本概念有一了解,然后我们在学习Spring AOP的时候,只需要“对号入座”就可以啦;

嘿嘿,还记得我们是怎么学习Spring IoC的吗?没错,就是从一般(通用概念)到特殊(Spring的实现);这次也一样!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值