[Java] 从 class 文件看 cglib 对 MethodInterceptor 的处理 (下)

20 阅读1分钟

背景

[Java] 从 class 文件看 cglib 对 MethodInterceptor 的处理 (上) 一文中,我们已经初步探讨了下方这个问题,本文会继续探讨这个问题。

  • 为什么 net.sf.cglib.proxy.MethodInterceptor\text{net.sf.cglib.proxy.MethodInterceptor} 可以调用动态代理类的基类(即例子中的 org.example.Adder\text{org.example.Adder} 类)中的方法

结合 [Java] 如何通过 cglib 的 FastClass 调用一个类中的“任意”方法? 一文的内容,可知 ⬇️

  • net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass} 可以为 org.example.Adder\text{org.example.Adder} 中定义的非私有方法分配编号(index\text{index})
  • 通过使用这个编号(index\text{index}),我们可以调用 org.example.Adder\text{org.example.Adder} 中对应的方法

要点

image.png

正文

项目结构

项目结构和 [Java] 从 class 文件看 cglib 对 MethodInterceptor 的处理 (上) 一文相同,可以参考那篇文章里的 项目结构 这一小节。

分析

两个 FastClass\text{FastClass}

[Java] 如何通过 cglib 的 FastClass 调用一个类中的“任意”方法? 一文中,我们已经了解到,对一个类 C\text{C} 而言,借助对应的 net.sf.cglib.reflect.FastClass:FastClassC\text{net.sf.cglib.reflect.FastClass}: \text{FastClass}_\text{C},我们可以(不通过反射)调用 C\text{C} 中定义的任意非私有方法。

如果我们既有和 org.example.Adder\text{org.example.Adder} 对应的 net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass},又有和 org.example.Adder\text{org.example.Adder} 的子类对应的 net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass},那么就可以自由调用我们在 org.example.Adder\text{org.example.Adder} 中定义的方法了 ⬇️

fc.png

类名对应的 FastClass 是什么
AdderAdder$$FastClassByCGLIB$$2ea8c1e0
Adder$$EnhancerByCGLIB$$82ff904 (Adder 的子类)Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd

FastClass\text{FastClass} 的这两个子类的名称太长了,为了便于描述,我们把它们分别简称为 ⬇️

  • FastClass1\text{FastClass}_1 (和 org.example.Adder\text{org.example.Adder} 对应)
  • FastClass2\text{FastClass}_2 (和 org.example.Adder\text{org.example.Adder} 的子类对应)

我们分别看看对应的代码是什么样子的

Adder 对应的 FastClass: FastClass1\text{FastClass}_1

org.example.Adder\text{org.example.Adder} 对应的 net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass}Adder$$FastClassByCGLIB$$2ea8c1e0 (简称为 FastClass1\text{FastClass}_1),借助 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: FastClass2\text{FastClass}_2

Adder$$EnhancerByCGLIB$$82ff904Adder 的子类,前者对应的 net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass}Adder$$EnhancerByCGLIB$$82ff904$$FastClassByCGLIB$$8d93dfdd(简称为 FastClass2\text{FastClass}_2),借助 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 的实例 ⬇️

image.png

Adder$$EnhancerByCGLIB$$82ff904add(int, int)\text{add(int, int)} 方法反编译的结果如下

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);
    }
}

其中 CGLIB$add$0$Proxy\text{CGLIB\textdollar add\textdollar 0\textdollar Proxy}net.sf.cglib.proxy.MethodProxy\text{net.sf.cglib.proxy.MethodProxy} 的实例

image.png

net.sf.cglib.proxy.MethodProxy\text{net.sf.cglib.proxy.MethodProxy} 中有 FastClassInfo\text{FastClassInfo} 类型的 fastClassInfo\text{fastClassInfo} 字段。就 CGLIB$add$0$Proxy\text{CGLIB\textdollar add\textdollar 0\textdollar Proxy} 而言,当它的 fastClassInfo\text{fastClassInfo} 字段计算好之后,fastClassInfo\text{fastClassInfo} 字段的内容会是这样的 ⬇️

fastClassInfo\text{fastClassInfo} 中的字段名称这个字段的类型对应的值
f1\text{f1}net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass}FastClass1\text{FastClass}_\text{1} 的实例 (和 org.example.Adder\text{org.example.Adder} 对应)
f2\text{f2}net.sf.cglib.reflect.FastClass\text{net.sf.cglib.reflect.FastClass}FastClass2\text{FastClass}_\text{2} 的实例 (和 org.example.Adder\text{org.example.Adder} 的子类对应)
i1\text{i1}int\text{int}00 (和 Adder\text{Adder} 中的 add(int, int)\text{add(int, int)} 方法对应)
i2\text{i2}int\text{int}1414 (在您的电脑上,有可能是其他值,它和 Adder\text{Adder} 子类中的 CGLIB$add$0(int, int)\text{CGLIB\textdollar add\textdollar 0(int, int)} 方法对应)

其他

画 "要点" 一图所用到的代码

@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