背景
在 [Java] 从 class 文件看 cglib 对 MethodInterceptor 的处理 (上) 一文中,我们已经初步探讨了下方这个问题,本文会继续探讨这个问题。
- 为什么 可以调用动态代理类的基类(即例子中的 类)中的方法
结合 [Java] 如何通过 cglib 的 FastClass 调用一个类中的“任意”方法? 一文的内容,可知 ⬇️
- 可以为 中定义的非私有方法分配编号()
- 通过使用这个编号(),我们可以调用 中对应的方法
要点
正文
项目结构
项目结构和 [Java] 从 class 文件看 cglib 对 MethodInterceptor 的处理 (上) 一文相同,可以参考那篇文章里的 项目结构 这一小节。
分析
两个
在 [Java] 如何通过 cglib 的 FastClass 调用一个类中的“任意”方法? 一文中,我们已经了解到,对一个类 而言,借助对应的 ,我们可以(不通过反射)调用 中定义的任意非私有方法。
如果我们既有和 对应的 ,又有和 的子类对应的 ,那么就可以自由调用我们在 中定义的方法了 ⬇️
| 类名 | 对应的 FastClass 是什么 |
|---|---|
Adder | Adder$$FastClassByCGLIB$$2ea8c1e0 |
Adder$$EnhancerByCGLIB$$82ff904 (Adder 的子类) | Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd |
的这两个子类的名称太长了,为了便于描述,我们把它们分别简称为 ⬇️
- (和 对应)
- (和 的子类对应)
我们分别看看对应的代码是什么样子的
Adder 对应的 FastClass:
对应的 是 Adder$$FastClassByCGLIB$$2ea8c1e0 (简称为 ),借助 IntelliJ IDEA (Community Edition) 可以看到 Adder$$FastClassByCGLIB$$2ea8c1e0.class 反编译的结果。完整的结果比较长,与本文相关的内容如下(不相关的内容用 ... 表示)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.example;
...
public class Adder$$FastClassByCGLIB$$2ea8c1e0 extends FastClass {
...
public int getIndex(String var1, Class[] var2) {
switch (var1.hashCode()) {
...
case 96417:
if (var1.equals("add")) {
switch (var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("int")) {
return 0;
}
}
}
break;
...
}
...
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
Adder var10000 = (Adder)var2;
int var10001 = var1;
try {
switch (var10001) {
case 0:
return new Integer(var10000.add(((Number)var3[0]).intValue(), ((Number)var3[1]).intValue()));
...
}
}
...
}
...
}
Adder 的子类对应的 FastClass:
Adder$$EnhancerByCGLIB$$82ff904 是
Adder 的子类,前者对应的 是 Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd(简称为 ),借助 IntelliJ IDEA (Community Edition) 可以看到 Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd.class 反编译的结果。完整的结果比较长,与本文相关的内容如下(不相关的内容用 ... 表示)
(在您的电脑上,Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd.class 的内容可能会有差异)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.example;
...
public class Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd extends FastClass {
...
public int getIndex(String var1, Class[] var2) {
switch (var1.hashCode()) {
...
case 96417:
if (var1.equals("add")) {
switch (var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("int")) {
return 4;
}
}
}
break;
...
case 1108311562:
if (var1.equals("CGLIB$add$0")) {
switch (var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("int")) {
return 17;
}
}
}
break;
...
}
...
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
// 由于反编译的结果对 '$' 的处理有点 bug,我手动调整了下一行的内容
Adder$$EnhancerByCGLIB$$82ff904 var10000 = (Adder$$EnhancerByCGLIB$$82ff904)var2;
int var10001 = var1;
try {
switch (var10001) {
...
case 4:
return new Integer(var10000.add(((Number)var3[0]).intValue(), ((Number)var3[1]).intValue()));
...
case 17:
return new Integer(var10000.CGLIB$add$0(((Number)var3[0]).intValue(), ((Number)var3[1]).intValue()));
...
}
}
...
}
...
}
AdderFactory 中的 methodInterceptor
AdderFactory 中的 methodInterceptor 字段对应的代码如下
private static final MethodInterceptor methodInterceptor =
(obj, method, args, proxy) -> {
if (method.getName().equals("add")) {
String message = String.format("The arguments for the add method are: %s",
Arrays.toString(args));
System.out.println(message);
}
return proxy.invokeSuper(obj, args);
};
当我们运行 AdderFactoryTest 中的 testBuildAdder 方法时,adder 会是 Adder$$EnhancerByCGLIB$$82ff904 的实例 ⬇️
Adder$$EnhancerByCGLIB$$82ff904 的 方法反编译的结果如下
public final int add(int var1, int var2) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
// 为了让代码便于阅读,我调整了下方代码的缩进风格
Object var3 = var10000.intercept(
this,
CGLIB$add$0$Method,
new Object[]{new Integer(var1), new Integer(var2)},
CGLIB$add$0$Proxy
);
return var3 == null ? 0 : ((Number)var3).intValue();
} else {
return super.add(var1, var2);
}
}
其中 是 的实例
中有 类型的 字段。就 而言,当它的 字段计算好之后, 字段的内容会是这样的 ⬇️
| 中的字段名称 | 这个字段的类型 | 对应的值 |
|---|---|---|
| 的实例 (和 对应) | ||
| 的实例 (和 的子类对应) | ||
| (和 中的 方法对应) | ||
| (在您的电脑上,有可能是其他值,它和 子类中的 方法对应) |
其他
画 "要点" 一图所用到的代码
@startmindmap
title 要点
* <i>Adder</i> 类中定义了 <b><i>add(int, int)</i></b> 方法
*:<i>cglib</i> 为 <i>Adder</i> 类生成的子类: <i>Adder<sub>enhancer</sub></i> 中
有这些方法 <:point_right:>;
** <b><i>CGLIB$add$0(int, int)</i></b>
** <b><i>add(int, int)</i></b>
* <i>Adder</i> 类的子类 <i>Adder<sub>enhancer</sub></i> 中有 <i>MethodProxy</i> 类型的 <b><i>CGLIB$add$0$Proxy</i></b> 字段
*:使用 <b><i>CGLIB$add$0$Proxy</i></b> 来调用 <b><i>invokeSuper(Object obj, Object[] args)</i></b> 方法时,
其逻辑会转化为 <:point_down:>
((Adder<sub>enhancer</sub>) obj).CGLIB$add$0(
((Number) args[0]).intValue(),
((Number) args[1]).intValue()
) ;
*:使用 <b><i>CGLIB$add$0$Proxy</i></b> 来调用 <b><i>invoke(Object obj, Object[] args)</i></b> 方法时,
其逻辑会转化为 <:point_down:>
((Adder) obj).add(
((Number) args[0]).intValue(),
((Number) args[1]).intValue()
);
@endmindmap
画 "对 FastClass 的使用" 一图所用到的代码
@startuml
'https://plantuml.com/class-diagram
title 对 <i>FastClass</i> 的使用
caption 图中只画了本文关心的内容\n<i>FastClass</i> 和它的子类, 在图中用 <b>粉色</b> 标出来了
class org.example.Adder
class org.example.Adder$$EnhancerByCGLIB$$82ff904
org.example.Adder <|-- org.example.Adder$$EnhancerByCGLIB$$82ff904
class org.example.Adder {
+ int add(int a, int b)
}
class org.example.Adder$$EnhancerByCGLIB$$82ff904 {
- MethodInterceptor CGLIB$CALLBACK_0
- {static} final MethodProxy CGLIB$add$0$Proxy
+ final int add(int, int)
final int CGLIB$add$0(int, int)
}
abstract class net.sf.cglib.reflect.FastClass #pink {
+ {abstract} int getIndex(String name, Class[] parameterTypes)
+ {abstract} Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException
}
class org.example.Adder$$FastClassByCGLIB$$2ea8c1e0
net.sf.cglib.reflect.FastClass <|-- org.example.Adder$$FastClassByCGLIB$$2ea8c1e0
class org.example.Adder$$FastClassByCGLIB$$2ea8c1e0 #pink {
+ int getIndex(String, Class[])
+ Object invoke(int, Object, Object[]) throws InvocationTargetException
}
note top of org.example.Adder$$FastClassByCGLIB$$2ea8c1e0
它为 <i>org.example.Adder</i> 中的
一些方法分配了编号 (<i>index</i>) <:point_down:>
| <b>方法</b> | <b>对应的 <i>index</i></b> |
| <b><i>add(int, int)</i></b> | <b><i>0</i></b> |
|...|...|
end note
class org.example.Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd
net.sf.cglib.reflect.FastClass <|-- org.example.Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd
class org.example.Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd #pink {
+ int getIndex(String, Class[])
+ Object invoke(int, Object, Object[]) throws InvocationTargetException
}
note top of org.example.Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd
它为 <i>org.example.Adder</i> 的 <b>子类</b> 中的
一些方法分配了编号 (<i>index</i>) <:point_down:>
(在您的电脑上, 对应的 <i>index</i> 也许会有差异)
| <b>方法</b> | <b>对应的 <i>index</i></b> |
|...|...|
| <b><i>add(int, int)</i></b> | <b><i>4</i></b> |
|...|...|
| <b><i>CGLIB$add$0(int, int)</i></b> | <b><i>17</i></b> |
|...|...|
end note
org.example.Adder <.. org.example.Adder$$FastClassByCGLIB$$2ea8c1e0 : 和 <b><i>org.example.Adder</i></b> 对应
org.example.Adder$$EnhancerByCGLIB$$82ff904 <.. org.example.Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd : 和 <b><i>org.example.Adder$$EnhancerByCGLIB$$82ff904</i></b> 对应
@enduml
画 "MethodProxy 中的 FastClassInfo" 一图所用到的代码
@startuml
title <i>MethodProxy</i> 中的 <i>FastClassInfo</i>
caption 图中只画了本文关心的内容
class net.sf.cglib.proxy.MethodProxy {
- volatile FastClassInfo fastClassInfo
}
class net.sf.cglib.proxy.MethodProxy$FastClassInfo {
FastClass f1
FastClass f2
int i1
int i2
}
object o {
f1: <i>FastClass<sub>1</sub></i> 的实例
f2: <i>FastClass<sub>2</sub></i> 的实例
i1: 0 (和 <i>Adder</i> 类中的 <b><i>add(int, int)</i></b> 方法对应的 <b><i>index</i></b> 的值)
i2: 17 (和 <i>Adder</i> 类子类中的 <b><i>CGLIB$add$0(int, int)</i></b> 方法对应的 <b><i>index</i></b> 的值)
}
o ..> net.sf.cglib.proxy.MethodProxy$FastClassInfo: <i>o</i> 是 <i>net.sf.cglib.proxy.MethodProxy$FastClassInfo</i> 的实例
note as n1
<i>o</i> 和 <b><i>Adder$$EnhancerByCGLIB$$82ff904</i></b> 类的
<b><i>CGLIB$add$0$Proxy</i></b> 字段持有相同的引用
end note
o .. n1
@enduml