Spring Aop Cglib Jdk问题

太乱不看版总结:

​ Spring 的 AOP都是用代理实现的 代理是无法拦截 内部调用

​ 如果要拦截内部调用 就得编译时织入(修改字节码 修改目标对象)

SpringBoot2 默认就使用 Cglib 进行 AOP

可以在注入的Bean getClass().getName() 查看 名称肯定都带有 $$EnhancerBySpringCGLIB$$fda183c9

百度 SpringBoot AOP无法拦截类内部的调用方法 很多都甩锅JDK代理 说使用Cglib就没问题

现在默认就是 cglib 但使用时还是碰到内部类无法被拦截的问题

实测添加注解

@EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

无效

比如 https://blog.csdn.net/piaoslowly/article/details/81743692 讲的非常详细

https://blog.csdn.net/dm_vincent/article/details/57526325

关于动态代理和CGLIB这两种方式的简要总结如下:

  • JDK动态代理(Dynamic Proxy)
    • 基于标准JDK的动态代理功能
    • 只针对实现了接口的业务对象
  • CGLIB
    • 通过动态地对目标对象进行子类化来实现AOP代理,上面截图中的SampleBean$$EnhancerByCGLIB$$1767dd4b即为动态创建的一个子类
    • 需要指定@EnableAspectJAutoProxy(proxyTargetClass = true)来强制使用
    • 当业务对象没有实现任何接口的时候默认会选择CGLIB

Spring 的 AOP 都是基于动态代理

所以是无法解决 内部接口调用

即使是CGLIB也是使用了动态代理

最大的区别在于两者实现AOP的底层原理不太一样:

  • Spring AOP: 基于代理(Proxying)
  • AspectJ: 基于字节码操作(Bytecode Manipulation)

如果非要动态调用内部的 就得使用 AspectJ

CGLIB 为什么也不能代理

这篇文章讲的很详细

https://blog.csdn.net/luanlouis/article/details/24589193

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package samples;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Programmer$$EnhancerByCGLIB$$fa7aa2cd extends Programmer
implements Factory
{
//......省略
private MethodInterceptor CGLIB$CALLBACK_0; // Enchaner传入的methodInterceptor
// ....省略
public final void code()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);//若callback 不为空,则调用methodInterceptor 的intercept()方法
}
if (this.CGLIB$CALLBACK_0 != null)
return;
//如果没有设置callback回调函数,则默认执行父类的方法
super.code();
}
//....后续省略

CGLIB 生成出来的动态代理类 也不能拦截到你内部调用

因为他也只是继承目标类 并不是修改目标类

AspectJ 就像 Javassist 是编译时直接修改了目标类 而不是继承目标对象进行拦截