# AOP

# JDK 动态代理原理

JDK 内部实现是通过反射,通过获取到目标对象类加载器,目标对象实现接口,和 InvocationHandler 来实现增强.

JDK 动态生成类手动实现 :

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//继承Proxy类, Proxy类中有InvocationHandler实例, 所以子类中不需要创建了
//实现了目标对象接口, 并生成方法, 但是方法内部并没有任何和目标类方法中近似的代码, 而是在方法中调用Invocationhandler的invoke方法
public class $Proxy0 extends Proxy implements A04Application.Foo {
static Method foo;
static Method bar;

//通过读取到的类的信息生成Method对象, 但是这里的代码并没有这样做, 直接写的Target.class
static {
try {
foo = A04Application.Target.class.getMethod("foo");
bar = A04Application.Target.class.getMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}

protected $Proxy0(InvocationHandler h) {
super(h);
}

@Override
public void foo() {
Object invoke = null;
try {
//直接调用invocationHandler中的invoke方法, 即自己写的增强方法
invoke = h.invoke(this, foo, new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}

@Override
public int bar() {
Integer invoke = null;
try {
invoke = (Integer) h.invoke(this, bar, new Object[0]);
return invoke;
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
}

# CGLib 动态代理原理

CGLib 实现动态代理的方式是继承,可以选择反射或是不反射,以下是动态生成的代理对象 (Arthas 反编译生成), 代码特别长,这里删除了大部分,只保留了关键部分

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0
extends CglibProxyDemo.Target
implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$foo$0$Method;
private static final MethodProxy CGLIB$foo$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;

public CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0() {
CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0 cglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0 = this;
CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0.CGLIB$BIND_CALLBACKS(cglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0);
}

//运行静态块
static {
CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0.CGLIB$STATICHOOK1();
}

public final void foo() {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
//这里和上面JDK动态代理差不多, 直接调用MethodInterceptor的intercept方法进行处理, 后续如果通过Method反射运行代码, 就和JDK动态代理一样了, 我们需要重点学习的是MethodProxy是如何生成的, 即如何不通过反射进行增强
Object object = methodInterceptor.intercept(this, CGLIB$foo$0$Method, CGLIB$emptyArgs, CGLIB$foo$0$Proxy);
return;
}
super.foo();
}

//此方法用于根据目标类生成所有方法的Method对象以及MethodProxy对象
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class<?> clazz = Class.forName("com.wong.aop.a03.CglibProxyDemo$Target$$EnhancerByCGLIB$$c757d8f0");
Class<?> clazz2 = Class.forName("java.lang.Object");
Method[] methodArray = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, clazz2.getDeclaredMethods());
CGLIB$equals$1$Method = methodArray[0];
CGLIB$equals$1$Proxy = MethodProxy.create(clazz2, clazz, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = methodArray[1];
CGLIB$toString$2$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = methodArray[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(clazz2, clazz, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = methodArray[3];
CGLIB$clone$4$Proxy = MethodProxy.create(clazz2, clazz, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
clazz2 = Class.forName("com.wong.aop.a03.CglibProxyDemo$Target");
CGLIB$foo$0$Method = ReflectUtils.findMethods(new String[]{"foo", "()V"}, clazz2.getDeclaredMethods())[0];
CGLIB$foo$0$Proxy = MethodProxy.create(clazz2, clazz, "()V", "foo", "CGLIB$foo$0");
}

final int CGLIB$hashCode$3() {
return super.hashCode();
}

final Object CGLIB$clone$4() throws CloneNotSupportedException {
return super.clone();
}
}

我们接着来看看 MethodProxy 是如何生成的,在上面代码中,可以看到此类写法 : MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper");

其中的参数意义为 :

  1. 目标类
  2. 代理类
  3. 方法描述
  4. 带增强功能的方法的名称
  5. 带原始功能方法的名称

我们接下来来看看如何生成的 MethodProxy

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//create方法
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
//生成增强方法描述(原方法名)
proxy.sig1 = new Signature(name1, desc);
//生成原始方法描述(非原方法名)
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}

//继续追踪proxy.createInfo = new CreateInfo(c1, c2); 这一行

//CreateInfo为MethodProxy静态内部类
private static class CreateInfo {
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;

public CreateInfo(Class c1, Class c2) {
//目标类
this.c1 = c1;
//代理类
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
this.namingPolicy = fromEnhancer.getNamingPolicy();
this.strategy = fromEnhancer.getStrategy();
this.attemptLoad = fromEnhancer.getAttemptLoad();
}

}
}

//接下来查看MethodProxy调用invoke及invokeSuper的方法

//invoke方法
//参数1 : 目标对象, 参数2 : 方法参数
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
//1. 继续追踪init()方法
this.init();
//6. 赋值
FastClassInfo fci = this.fastClassInfo;
//7. 调用目标类fastClass中invoke方法
//参数1 : 原方法名索引, 参数2 : 目标对象, 参数3 : 方法参数
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}

//invokeSuper方法
//参数1 : 代理对象, 参数2 : 方法参数
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
FastClassInfo fci = this.fastClassInfo;
//8. 调用代理类fastClass中的invoke方法
//参数1 : 非原方法名索引, 参数2 : 代理对象, 参数3 : 方法参数
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}

//2. init()方法
private void init() {
//3. 查看以下fastClassInfo类的结构
//5. 判断是否生成了fastClassInfo
if (this.fastClassInfo == null) {
//双检锁
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
CreateInfo ci = this.createInfo;
FastClassInfo fci = new FastClassInfo();
//根据目标类生成fastClass
fci.f1 = helper(ci, ci.c1);
//根据代理类生成fastClass
fci.f2 = helper(ci, ci.c2);
//通过增强方法(原方法名)描述获取其索引
fci.i1 = fci.f1.getIndex(this.sig1);
//通过原始方法(非原方法名)描述获取其索引
fci.i2 = fci.f2.getIndex(this.sig2);
//接着回去看6
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}

//4. fastClassInfo类结构
//可以看到, fastClassInfo类就是储存两个fastClass与方法索引的, 接着继续回去看5
private static class FastClassInfo {
FastClass f1;
FastClass f2;
int i1;
int i2;

private FastClassInfo() {
}
}

可以看到,最终都是调用了 fastClass 中的 invoke 方法,只是调用的 fastClass 与方法索引不同,那么这个 fastClass 又是什么东西呢

以下为手动实现 targetFastClass (目标对象 fastClass)

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
32
33
34
35
36
37
38
39
40
public class TargetFastClass {
//目标对象所有方法的描述信息
private Signature s0 = new Signature("save", "()V");
private Signature s1 = new Signature("save", "(I)V");
private Signature s2 = new Signature("save", "(J)V");

//根据描述信息返回对应方法的索引
public int getIndex(Signature signature) {
if (s0.equals(signature)) {
return 0;
} else if (s1.equals(signature)) {
return 1;
} else if (s2.equals(signature)) {
return 2;
}
return -1;
}

//参数1 : 方法索引, 参数2 : 目标对象, 参数3 : 方法参数
public Object invoke(int index, Object target, Object[] objects) {
//根据不同的方法索引, 通过目标对象调用不同的方法
if (index == 0) {
((Target)target).save();
return null;
} else if (index == 1) {
((Target)target).save((Integer) objects[0]);
return null;
} else if (index == 2) {
((Target)target).save((Long) objects[0]);
return null;
}
throw new RuntimeException("无此方法");
}

public static void main(String[] args) {
TargetFastClass fastClass = new TargetFastClass();
int index = fastClass.getIndex(new Signature("save", "()V"));
fastClass.invoke(index, new Target(), new Object[100]);
}
}

以下为手动实现 proxyFastClass (代理对象 fastClass)

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
32
33
34
35
36
37
38
39
40
41
public class ProxyFastClass {
//代理对象所有方法的描述信息
//可以观察到, 这里的描述信息是saveSuper, 而代理对象的saveSuper方法中, 直接调用父类super.save()对应方法
private Signature s0 = new Signature("saveSuper", "()V");
private Signature s1 = new Signature("saveSuper", "(I)V");
private Signature s2 = new Signature("saveSuper", "(J)V");

//根据描述信息返回对应方法的索引
public int getIndex(Signature signature) {
if (s0.equals(signature)) {
return 0;
} else if (s1.equals(signature)) {
return 1;
} else if (s2.equals(signature)) {
return 2;
}
return -1;
}

//参数1 : 方法索引, 参数2 : 代理对象, 参数3 : 方法参数
public Object invoke(int index, Object proxy, Object[] objects) {
if (index == 0) {
((Proxy)proxy).saveSuper();
return null;
} else if (index == 1) {
((Proxy)proxy).saveSuper((Integer) objects[0]);
return null;
} else if (index == 2) {
((Proxy)proxy).saveSuper((Long) objects[0]);
return null;
}
throw new RuntimeException("无此方法");
}

public static void main(String[] args) {
ProxyFastClass fastClass = new ProxyFastClass();
int index = fastClass.getIndex(new Signature("saveSuper", "()V"));
fastClass.invoke(index, new Proxy(null), new Object[100]);
}
}

以上可以看出,methodProxy 通过内部维护两个 fastClass 的方式,保存了目标类和代理类的所有方法映射信息,而代理类又对每个方法维护了一个 methodProxy, 但是每个 methodProxy 在 CGLib 中只会调用一个方法,如下图所示

CGLib代理类

# Spring 选择代理

  • proxyTargetClass = false 且目标实现了接口,用 JDK 实现
  • proxyTargetClass = false 且目标没有实现接口,用 cglib 实现
  • proxyTargetClass = true, 总是用 cglib 实现

# 高级 Aspect 转低级 advisor 代理创建时机

  1. 初始化之后 (无循环依赖时)
  2. 实例化之后,依赖注入前 (有循环依赖时), 并暂存于二级缓存