OOP无法解决类似于日记、安全检查等系统功能散落在系统中的问题,AOP则可以对这些需求进行模块化的组织,AOP引入Aspect以模块化的形式对系统中的横切关注点进行封装,Aspect对于AOP,就像Class对于OOP,AOP只是对于OOP的一种补足
AOP只是一种概念,可以使用不同的语言来实现这个概念,并且可以和系统语言不同,实现AOP的语言称为AOL,例如如果业务需求系统实现使用的是Java,系统需求实现使用的则可以是C实现的AOP,最后通过Weave过程将两个组件集成到一个系统
AOP经过了两个阶段
- 静态AOP时代:相应的横切关注点以Aspect实现之后,通过特定的编译器,将实现后的Aspect编译到系统的静态类中,达到融合Aspec和Class的目的。这种方式的优点就是Aspect直接以Java字节码的形式编译到Java类中吗,JVM像普通类一样加载类运行。缺点是横切关注点需要改变织入的位置时,就需要重新编写、编译
- 动态AOP时代:由于Java提供的动态特性,大多数AOP都是由Java实现,各种概念实体就是普通的Java类。和静态AOP不同的是AOP的织入过程在系统运行开始之后,并且织入信息大都是采用外部XML文件格式存储,可以在不改变其他模块的同时,实现调整织入点一级织入逻辑单元。缺点就是对AOP类加载都在系统运行期间,会有部分性能损失
Java上AOP实现机制
- 动态代理:将横切关注点逻辑封装到动态代理的
InvocationHandler
中,然后再系统运行期间,根据横切关注点需要织入的模块位置,将横切逻辑织入到相应的代理类中 - 动态字节码增强:可以为需要织入横切逻辑的模块类在运行期间,通过动态字节码增强技术,为这些系统模块类生成相应的子类,并将横切逻辑加到这些子类中,让应用程序在执行期间使用的是这些动态生成的子类,从而达到将横切逻辑织入系统的目的
- 自定义类加载器:通过读取外部文件规定的织入规则和必要信息,在加载Class文件期间就可以将横切逻辑添加到系统模块类的现有逻辑中,再将改动后的Class交给JVM执行。这种方法最大的问题是某些应用服务器会控制整个类加载体系
- AOL扩展:AOP各种概念在AOL中都有意义对应的实体,可以使用扩展过的AOL,实现任何AOP甚至OOP概念实体
AOP成员
- Joinpoint:要在其之上进行织入操作的系统执行点,基本上只要允许,程序执行过程中的任何时点都可以作为横切逻辑的织入点。如方法调用、方法调用执行、构造方法调用、字段设置、字段获取、异常处理执行和类初始化等
- Pointcut:需要参照Pointcut规定的信息,草才最终知道应该往系统的哪些Joinpoint上织入横切逻辑,Pointcut有几种表达形式,如正则表达式、使用特定的Pointcut表述语言,这些表达式之间也可以做运算
- Advice:是单一横切关注点逻辑的载体,代表将会织入Joinpoint的横切逻辑,Aspect如果是OOP中的Class,Advice就是Class中的Method
- Aspect:是对系统中的横切关注点逻辑进行模块化封装的AOP概念实体
- 织入和织入器:织入是OOP和AOP之间的桥梁,AspectJ有专门的编译器完成织入操作,Spring APO使用ProxyFactory这组类完成织入,不管形式如何,相同的职责都是完成横切关注点逻辑到系统的最终织入
- 目标对象:被织入横切逻辑的对象
其中Advice成员根据在Joinpoint位置执行时机的差异或者完成功能的不同,可分成不同的形式
- Before Advice:在Joinpoint位置之前执行,可以使用该方法做一些系统初始化的工作,如设置系统初始值
- After Advice:又可以细分为After returning Advice在Joinpoint正常完成执行流程之后才会执行,After throwing Advice在Joinpoint抛出异常才会执行,After Advice和finally块一样,不管正常执行还是抛出异常都会执行
- Around Advice:可以在Joinpoint之前和之后都能执行相应的逻辑