AOP——深度解析一

为什么出现AOP?

对于OOP我们可以将各个需求模块化,但是对于监控埋点、日志、安全校验等,通常是在每个模块中散落,没有很好的方法把这些横切关注点模块化,并统一抽象管理。所以AOP引入Aspect概念,用来对这些横切关注点进行封装。Aspect对于AOP,就类似于Class对于OOP。
这里写图片描述

AOP的演变

静态AOP:AspectJ

在编译期,在字节码的粒度上,修改原有calss把Aspect融入class(ao组件集成到oop组件的过程中,在aop中成为织入),对jvm完全透明。

  • 缺点:不够灵活,aspect织入位置变化,需要修改后重新编译

  • 优点:织入过程对JVM完全透明,没有任何性能损耗。

动态AOP:SpringAOP等aop框架

在运行时开始织入,而不是编译期,织入信息大多使用xml配置,对现有代码侵入性低。对织入位置的改变,不会影响其余系统模块。甚至可以在运行时动态更改。

  • 优点:灵活,易用,侵入性低

  • 缺点:运行期对字节码操作,会有性能有损耗。但随着JVM反射机制的优化,这种损耗可以容忍。

AOP实现原理

JDK动态代理:可以在运行时为接口生成代理对象。针对接口

运行期,为一个接口生成代理对象,并且

		/**
		 * java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class
		 * <?>[] interfaces, InvocationHandler h)
		 * 
		 * 生成一个针对某个接口的代理类,
		 * 对接口方法的调用都会分发代理中一个指定的invocationHandler
		 */

public class SetProxyFactory {
    public static Set getSetProxy(final Set s) {
        return (Set) Proxy.newProxyInstance
          (s.getClass().getClassLoader(),
                new Class[] { Set.class },
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, 
                      Object[] args) throws Throwable {
                        return method.invoke(s, args);
                    }
                });
    }
}

动态构建字节码,字节码增强

使用cglib等工具,在运行时动态的生成一个“子类”,这个子类织入了aspect逻辑。通过使用这个子类,实现了aspect的横向融合。

与jdk动态代理的最大区别,不需要针对接口构造代理,其实某个对象没有实现任何接口,也可以生成织入横切逻辑的代理对象。
缺点:被代理的类不能是final类;其中的方法如果声明了final也无法被拦截

在Spring中默认会采用JDK动态代理,如果JDK动态代理无法使用则会自动使用cglib实现动态代理。

自定义classLoader,字节码增强

通过自定义classLoader,并在这个classLoader中把原有的字节码 修改为 增加了横切逻辑的字节码,然后把这个修改后的字节码 载入JVM中实现。偷梁换柱!
这里写图片描述

这中实现功强大彻底,但有些服务器会有统一的classLoader,此时可能无法使用自定义classLoader。

AOL 如AspectJ

AOL:面向切面编程的语言。通过使用AOL,对aop各个概念(如pointcut等等)建模(比如java实现的aspectJ).

AOP术语

Joinpoint

将AOP模块织入到OOP模块肯定会考虑具体在程序哪些执行位置织入,这些织入位置就是JoinPoint

  • JoinPoint类型

    • Method Call:某个方法被调用的位置
      这里写图片描述

    • Method Call execution :某个方法被 内部 执行的位置
      这里写图片描述

    • Field Set: 对象某个属性赋值 的位置,可以是setter方法 也可以是直接赋值

    • Field Get: 对象某个属性赋值 的位置,可以是getter方法 也可以是直接获取

    • Exection Handler execution :某个异常抛出,对这个异常处理的 位置

    • Class Initialization:类初始化的时候,具体就是 类的静态变量、静态块初始化(http://blog.csdn.net/lemon89/article/details/47363127)。

其实程序运行中的任何一点都可以作为JoinPoint,只是对于某些位置,AOP产品并不是很容易捕获。

Pointcut

pointcut概念代表了Joinpoint的表达方式,比如一个程序里有很多想要加入横切逻辑的点,怎么表达呢?就用到了pointcut
Pointcut代表了一组或一系列的JoinPoint.

  • Pointcut的表示方式:

    • 直接指定这个joinpoint所在的方法名称,如 com.abc.HelloBean.helloMethod。比较麻烦,joinPoint越多越麻烦,你要一个个指定。

    • 正则表达式 SpringAOP就是支持的

    • 特定Pointcut表达式 AspectJ使用了这种方式,类似于正则表达式,针对于Pointcut的表达式并且有实现解释器。SpringAOP也支持

  • Pointcut的逻辑运算:
    比如声明了两个Pointcut: Pointcut.MethodA ,Pointcut.MethodA

通过运算,可以产生新的Pointcut:Pointcut.MethodA && Pointcut.MethodA;
Pointcut.MethodA || Pointcut.MethodA

具体更具实现产品不同而不同,Springxml中支持 and ;or等运算词;AspectJ则支持&& ;||等运算词

Advice

需要织入到Joinpoint 的具体的单一横切逻辑。根据这个切面逻辑在joinpoint 执行的时机、完成功能的不同,分为如下几类:

  • Before Advice:在joinpoint指定位置之前执行的切面逻辑。

  • After Advice:在joinpoint指定位置之后执行的切面逻辑。细分为如下几类:

    • After returning Advice:在joinpoint 正常执行完成 之后执行的切面逻辑。 比如方法正常结束,才会执行这个advice.
    • After throwing Advice:在joinpoint 没有正常执行完成并且抛出异常时 执行的切面逻辑。 比如方法抛出异常,才会执行这个advice.
    • After Advice:类似与Java中的finally块,无论异常与否都会被执行

这里写图片描述

  • Around Advice:在joinpoint指定位置 前后 执行的切面逻辑。
  • Introduction :与前面几个Advice不同,它不关注 joinpoint上执行的时机,而是关注所能对joinpoint添加的行为或特性而定义的。略

Aspect

对横切关注点模块化封装的实体概念。Aspect通常包含多个Pointcut以及相关Advice定义。

Target Object

将横切逻辑织入某个具体的对象,这个对象就是Target Object

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值