如何理解AOP
是什么
AOP即面向切面编程,是一种思想,是对OOP的补充。简单的来说就是把公共的逻辑抽离出来,
让开发者可以跟关注于业务逻辑的开发
说简单点AOP就是 在不惊动原有的代码的基础上对功能进行增强操作
概念:
连接点:JIONPoint,可以被AOP控制的方法(运行时刻被拦截到的方法)
通知:advice 增强,切面的具体行为
切入点:决定在哪些方法上生效
切面:描述切入点和通知的关系
通知类型:
@Before
@After
@AfterReturning
@AfterThrowing 在抛错之后
@Aroud 环绕通知:在目标方法执行之前和之后都能插入逻辑,甚至可以决定是否执行目标方法。
总结:

AOP的底层实现方法
一共有三种吧,常见的像代理,还有AspectJ框架提供的两种方法
第一种就是AJC增强,它就是指AJC编译器在编译过程中把通知的增强功能植入目标类的Class文件中
来达到增强的效果,然后它的执行时机就是通知类上有Aspect注解,不需要component注解,该通知类
就没有被Spring所管理。所有AOP的执行底层是通过AJC去修改Class文件,而不是动态代理,这时候没有
Spring容器也可以进行aop增强,但需要用到maven一个插件,这种方式用得很少
第二宗就是通过agent底层来实现aop,它是agent编译器在加载目标类的时候,因为是在加载类的时候么,
Class文件已经编译完了,它就在加载目标类的时候修改对应的Class文件,达到增强的功能。它的执行时机
跟AJC编译差不多的,也是通知类上有Aspect注解,不需要component注解。区别就是给JVM加一个参数 -
javaagent,后面指定maven目录下的一个jar包路径
第三种就是我们常用的代理增强了。代理的本质就是生成一个代理对象,类似于房东和中介的,中介就是代理
这个代理对象和切入点有着相同的方法,然后代理对象的方法就是根据需求增强过的,然后调用切入点的方法
不走它的方法,而是走代理对象在增强过的方法。而怎么保证代理对象和切入点有着相同的方法呢,这就分为
两派,一种是jdk代理,一种是cglib代理。
jdk代理是Java自带的代理,主要是采用了多态和反射的方式。它是代理对象和目标类实现同一个接口,就可
以保证两者都有同样的方法
jdk代理通过Proxy.newProxyInstance()获取到代理对象

newProxyInstance方法的三个参数:
第一个参数,类加载器
第二个参数,接口集合,因为jdk代理需要目标对象实现接口
第三个参数,一个函数式接口,实现增强方法逻辑,这个函数式接口也有三个参数:
第一个参数,目标对象
第二个参数,需要被增强的方法
第三个参数,方法执行的参数
proxy.newProxyInstance()方法底层会根据传入的接口集合,在运行时在本类目录下生成一个$proxy0类
实现这些方法,然后里面的所有方法都会被InvocationHandler方法给拦截下来进行增强(包括equals和hashcode)
1 | public final class $Proxy0 extends Proxy implements Test { |
cglib代理不是jdk自带的代理,需要导外部依赖,其底层是让代理类继承目标类,通过Enhancer.create获取代理对象

create方法的两个参数:
第一个参数:目标类
第二个参数:一个函数式接口,实现增强方法逻辑,这个函数式接口有四个参数:
第一个参数,代理对象自己
第二个参数,需要被增强的方法
第三个参数,方法执行的参数
第四个参数,MethodProxy,代理不走反射的关键
其实AOP的重点是如何获取目标类的原始方法,并把它放到特定的上下文环境下执行
对于这一点,jdk代理采用的是反射,你看,我都采用反射了,我还拿不到你原始方法吗
而cglib采用的就是继承,我都继承了,我肯定能通过super.xx拿到你的原始方法
还有就是,代理模式则是在运行期生成新的字节码。AspectJ对代码的侵入性很强,因此没有怎么流行 但因为它是在编译器和类加载期修改字节码,故性能较高。且能突破代理只能重写方法来实现增强的限 制,如能增强构造方法,静态方法,final修饰的方法

Spring的AOP是怎么实现的
Spring的AOP是采用动态代理实现的

至于是jdk还是cglib,Spring容器代理时,会有一个proxyBean类,这个类会传入目标对象和通知
,然后这个类还有一个boolean proxyTargetClass,如果设置为false,那就会去检查目标类是否实现了
接口,有就用jdk,无就用cglib。如果为true,那就直接用cglib
一个方法被多个切面AOP了?
需要给切面标明@Order(x)x越小,说明你那个优先级越高。
如果无标明,那就会按注册的顺序来执行,但此时是随机的,不可知的
因为 Spring AOP 内部会把所有的切面包装成 Advisor,然后放到一个集合里。虽然这个集合是个List,但
虽然用的是 ArrayList(顺序表),但插入顺序本身没保证稳定,因为:
- 不同 BeanFactory 扫描/注册 Bean 的顺序可能不同。
- 不同 JDK、不同文件系统,class 扫描顺序也可能不同。
- 所以“默认顺序”没有规范,才会被说成是 **不可知的**。
1 |
|

AOP失效?
当然这只限于代理类的
类中自调用方法,同一个类中A调用B方法,B方法的AOP不会生效
调用内部类方法
调用静态方法,静态方法不会被AOP
调用final方法,final方法不会被AOP
目标类不符合规则,如jdk代理时没继承接口,cglib代理时是final类
cglib 和jdk代理哪个快

在 JDK1.6、JDK1.7、JDK1.8 逐步对 JDK 动态代理优化之后,在调用次数较少的情况下,JDK 代理效率高于 CGLib 代理效率,只有当进行大量调用的时候,JDK1.6 和 JDK1.7 比 CGLib 代理效率低一点,但是到 JDK1.8 的时候,JDK 代理效率高于 CGLib 代理。所以如果有接口使用 JDK 动态代理,如果没有接口使用 CGLIB 代理。