Spring AOP 和 AspectJ是Java中最流行的 AOP 框架
AOP
AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指在编译阶段修改目标类字节码,属于静态编入,不需要代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。其中aspectj为静态代理,Spring AOP是动态代理
AOP核心概念
Advice:通知,是指拦截到jointpoint之后所要做的事情即特定的Jointpoint处运行的代码。JoinPoint:连接点,它定义在哪里(哪些点)加入你的逻辑功能,基本每个方法的前后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点PointCut:切入点的集合,即一组Joinpoint,就是说一个Advice可能在多个地方织入。比如一个类里,有15个方法,那就有几十个连接点了,让切点来筛选连接点,选中那几个你想要的方法。Aspect:切面,实际是通知和切入点的组合,通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等),而切入点说明了在哪干(指定到底是哪个方法)。Weaving:织入,把切面应用到目标对象来创建新的代理对象的过程。
Aspectj
ApectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类。

举例
安装 AspectJ 见:https://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/index.html
- 业务逻辑
|
|
- 切面
Aspect
使用AspectJ编写一个Aspect
|
|
ajc编译
|
|
|
|
可以发现切面代码织入了HelloWorld.class
|
|
从Aspect编译后的class文件可以更明显的看出执行的逻辑。proceed方法就是回调执行被代理类中的方法。
- 执行结果
|
|
Spring AOP
Spring AOP使用的是动态代理增强,动态代理不会改变类的字节码,而是动态的生成代理对象。Spring AOP的动态代理机制有两种方式:JDK动态代理和CGLIB动态代理。
JDK动态代理
JDK动态代理需要被代理的类必须实现一个接口,底层通过反射实现
CGLIB动态代理
CGLIB动态代理可以不用需要被代理类必须实现接口,底层通过继承实现,因此如果某个类被标记为
final,那么它是无法使用CGLIB做动态代理的

创建AOP代理
|
|
如果配置了<aop:aspectj-autoproxy proxy-target-class="true"/>或者目标类没有实现接口,则使用CGLIB代理;如果目标类实现了接口,默认使用JDK代理
Spring AOP vs ApectJ
Spring AOP 与 ApectJ 的目的一致,都是为了统一处理横切业务,但与AspectJ不同的是:
Spring AOP并不尝试提供完整的AOP功能,Spring AOP更注重的是与Spring IOC容器的结合,并结合该优势来解决横切业务的问题,因此在AOP的功能完善方面,相对来说AspectJ具有更大的优势。AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),而Spring回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别
注意:
Spring 2.0后便使用了与AspectJ一样的注解,新增了对AspectJ切点表达式支持。需要注意Spring 只是使用了与 AspectJ 一样的注解,但仍然没有使用 AspectJ 的编译器,底层仍然是动态代理技术的实现