AOP了解一下

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

AOP的存在价值

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

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

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

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



看到如图所示的示意图,可能有的读者发现这种做法的不足之处:如果有一天,图中的深色代码段需要修改,那就得同时修改3个地方,如果是100个地方,就很崩溃。

为了解决这个问题,我们可以将深色代码部分定义成一个方法,然后在3个代码段中分别调用该方法即可。


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

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

因为软件系统需求变更时很频繁的事,系统前期设计方法1,2,3时只实现了核心业务功能,过了一段时间,我们需要为方法1,2,3,都增加事务控制,然后又需要进行用户合法性验证,然后又要增加日志记录。。。。。。怎么办????

我们希望有一种特殊的方法:我们只要定义该方法,无须再方法1,2,3中显式调用它,系统会“自动”执行该特殊方法。

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

AOP术语

AOP有自己的术语,描述切面的常用术语有通知(advice),切点(pointcut)和连接点(join point)相关概念的关联如图所示。


大多数描述AOP功能的术语并不直观,尽管如此,他们现在已经是AOP的组成部分了,为了理解AOP,我们必须理解这些术语.

西安的夏天是很热的,所以空调是不可缺少的工具。空调的一个缺点就是很费电。每家每户都有一个电表用来记录本月的用电量。

切面(Aspect)

当抄表员开始一天的工作时,他知道自己要做的工作所需要的一切东西。切面是通知和切点的结合,通知和切点共同定义了切面的全部内容,它是什么,在何时和何处完成其功能。

通知(Advice)

当抄表员出现在我们家门口时,他很明确自己的工作是记录用户的用电量。

类似的,切面也有目标,他必须完成的工作。在AOP术语中,切面的工作被称为通知。通知定义了切面是什么以及何时使用。出了描述切面要完成的工作,通知还解决了何时执行这个问题。它应该应用在某个方法被调用之前还是之后,还是二者兼之,知识只在方法抛出异常时调用?

Spring切面可以应用的5种类型的通知:

(1)前置通知(Before)在目标方法被调用之前调用通知功能

(2)后置通知(After)在目标方法完成之后调用通知,此时不会关心方法的输出是什么。

(3)返回通知(After-returning)在目标方法成功执行之后调用通知

(4)异常通知(After-throwing)在目标方法抛出异常后调用通知;

(5)环绕通知(Around)通知报过了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

连接点(Join point)

电表可以看做电力公司与用户联系的通道,抄表员通过电表数字的读取记录用电量。同样,我们的应用如同一座城市,也有数以千计的时机应用通知,这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中。并添加新的行为。

切点(pointcut)

如果让一位抄表员访问所有客户显然不现实。实际上是每个人负责一定的区域。类似的,一个切面并不需要通知应用的所有连接点,切点有助于缩小切面所通知的连接点的范围。如果说通知定义了切面的“什么”“何时”的话,那么切点就定义了何处。切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。有些AOP框架允许我们创建动态的切点,可以根据运行时的决策(比如方法的参数值)来决定是否应用通知。

引入(Introduction)

引入允许我们向现有的类添加新的方法或属性。例如,我们可以创建一个NewAdvice通知类,该类记录了对象最后一次修改时的状态,这很简单,需要一个方法,setLastModified(Date)和一个实例变量来保存这个状态。然后这个新方法和实例变量就可以被引入到现有的类中。从而可以在无需修改这些现有的类的情况下,让他们具有新的行为和状态。

织入(Weaving)

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入:

1.编译期:切面在木败类编译时被织入,这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。

2.类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader)它可以再目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。

3.运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。

再看一下上面的图。总结一下,通知包含了需要用于多个应用对象的横切行为;连接点是程序执行过程中能够应用通知的所有点;切点定义了通知被应用的具体位置(在哪些连接点)。其中关键的概念是切点定义了哪些连接点会得到通知。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值