[Java] 从 class 文件看 cglib 对 Dispatcher 和 LazyLoader 的处理

19 阅读2分钟

背景

[Java] 从 class 文件看 cglib 对 InvocationHandler 的处理 一文所提到的, 使用 cglib 时,会用到 net.sf.cglib.proxy.Callback\text{net.sf.cglib.proxy.Callback} 的子接口 ⬇️

  • net.sf.cglib.proxy.MethodInterceptor\text{net.sf.cglib.proxy.MethodInterceptor}
  • net.sf.cglib.proxy.NoOp\text{net.sf.cglib.proxy.NoOp}
  • net.sf.cglib.proxy.LazyLoader\text{net.sf.cglib.proxy.LazyLoader}
  • net.sf.cglib.proxy.Dispatcher\text{net.sf.cglib.proxy.Dispatcher}
  • net.sf.cglib.proxy.InvocationHandler\text{net.sf.cglib.proxy.InvocationHandler}
  • net.sf.cglib.proxy.FixedValue\text{net.sf.cglib.proxy.FixedValue}

它们的简要类图如下 ⬇️ image.png

本文关心的是 👇

  • net.sf.cglib.proxy.LazyLoader\text{net.sf.cglib.proxy.LazyLoader}
  • net.sf.cglib.proxy.Dispatcher\text{net.sf.cglib.proxy.Dispatcher}

下图单独展示了 net.sf.cglib.proxy.Callback\text{net.sf.cglib.proxy.Callback} 和这两者的关系 👇

image.png

要点

Dispatcher 部分

dispatcher.png

LazyLoader 部分

lazy.png

代码

铺垫

下面举的例子有些牵强,因为我没有想出比较好的例子来 😂 大家凑合看吧。假设有一个 与门 的抽象类 ⬇️

public abstract class AbstractAndGate {
    private void validateInputLength(boolean[] input) {
        if (input.length == 0) {
            throw new IllegalArgumentException("Input should have at least 1 element!");
        }
    }

    public boolean calculate(boolean... input) {
        validateInputLength(input);

        for (boolean item : input) {
            if (!item) {
                return false;
            }
        }

        return true;
    }
}

AbstractAndGate 是抽象类,实际可用的 与门 是它的两个子类 ⬇️

  • CheapAndGate
  • ExpensiveAndGate

其中 CheapAndGate 的成本很低,即使在每次调用 calculate(boolean) 方法时,都创建新的 CheapAndGate 实例,也没问题。而 ExpensiveAndGate 的成本很高,我们希望最多只持有一个 ExpensiveAndGate 实例。

项目结构

我们在项目顶层执行 tree . 命令,会看到如下的结果 ⬇️

.
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── example
    │               ├── AbstractAndGate.java
    │               └── GateFactory.java
    └── test
        └── java
            └── org
                └── example
                    └── GateFactoryTest.java

10 directories, 4 files

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>cglib-study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <!-- Source: https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.5.5</version> <!-- Use a recent version -->
                <configuration>
                    <argLine>--add-opens=java.base/java.lang=ALL-UNNAMED</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

AbstractAndGate.java

package org.example;

public abstract class AbstractAndGate {
    private void validateInputLength(boolean[] input) {
        if (input.length == 0) {
            throw new IllegalArgumentException("Input should have at least 1 element!");
        }
    }

    public boolean calculate(boolean... input) {
        validateInputLength(input);

        for (boolean item : input) {
            if (!item) {
                return false;
            }
        }

        return true;
    }
}

/**
 * Assume that CheapAndGate is inexpensive,
 * and it is OK to create a new instance for {@link AbstractAndGate#calculate(boolean...)} call.
 */
final class CheapAndGate extends AbstractAndGate {

    public CheapAndGate() {
        System.out.println("CheapAndGate instance is being created");
    }

    @Override
    public String toString() {
        return "CheapAndGate";
    }
}

/**
 * Assume that ExpensiveAndGate is expensive,
 * and we need to cache it for {@link AbstractAndGate#calculate(boolean...)} calls.
 */
final class ExpensiveAndGate extends AbstractAndGate {

    public ExpensiveAndGate() {
        // Assume that there is some expensive work here
        System.out.println("ExpensiveAndGate instance is being created");
    }

    @Override
    public String toString() {
        return "ExpensiveAndGate";
    }
}

GateFactory.java

package org.example;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.LazyLoader;

public class GateFactory {

    static {
        // 将 cglib 生成的类保存到当前目录下
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, ".");
    }

    private static final Dispatcher dispatcher = CheapAndGate::new;

    private static final LazyLoader lazyLoader = ExpensiveAndGate::new;

    public static AbstractAndGate buildCheapAndGate() {
        return (AbstractAndGate) Enhancer.create(AbstractAndGate.class, dispatcher);
    }

    public static AbstractAndGate buildExpensiveAndGate() {
        return (AbstractAndGate) Enhancer.create(AbstractAndGate.class, lazyLoader);
    }
}

GateFactoryTest.java

package org.example;

import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.LazyLoader;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Field;

public class GateFactoryTest {

    @Test
    public void testBuildCheapAndGate() {
        AbstractAndGate cheapAndGate = GateFactory.buildCheapAndGate();
        Assert.assertFalse(cheapAndGate.calculate(false, false));
        Assert.assertFalse(cheapAndGate.calculate(false, true));
        Assert.assertTrue(cheapAndGate.calculate(true, true));
    }

    @Test
    public void testBuildExpensiveAndGate() {
        AbstractAndGate expensiveAndGate = GateFactory.buildExpensiveAndGate();
        Assert.assertFalse(expensiveAndGate.calculate(false, false));
        Assert.assertFalse(expensiveAndGate.calculate(false, true));
        Assert.assertTrue(expensiveAndGate.calculate(true, true));
    }

    @Test
    public void testDispatcher() throws ReflectiveOperationException {
        AbstractAndGate cheapAndGate = GateFactory.buildCheapAndGate();

        Field dispatcherField = GateFactory.class.getDeclaredField("dispatcher");
        dispatcherField.setAccessible(true);
        Dispatcher dispatcher = (Dispatcher) dispatcherField.get(null);

        Field cglibCallback0Field = cheapAndGate.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        cglibCallback0Field.setAccessible(true);
        Dispatcher cglibCallback0 = (Dispatcher) cglibCallback0Field.get(cheapAndGate);

        Assert.assertSame(cglibCallback0, dispatcher);
    }

    @Test
    public void testLazyLoader() throws ReflectiveOperationException {
        AbstractAndGate expensiveAndGate = GateFactory.buildExpensiveAndGate();

        Field lazyLoaderField = GateFactory.class.getDeclaredField("lazyLoader");
        lazyLoaderField.setAccessible(true);
        LazyLoader lazyLoader = (LazyLoader) lazyLoaderField.get(null);

        Field cglibLazyLoader0Field = expensiveAndGate.getClass().getDeclaredField("CGLIB$CALLBACK_0");
        cglibLazyLoader0Field.setAccessible(true);
        LazyLoader cglibLazyLoader0 = (LazyLoader) cglibLazyLoader0Field.get(expensiveAndGate);

        Assert.assertSame(cglibLazyLoader0, lazyLoader);
    }
}

AbstractAndGate/CheapAndGate/ExpensiveAndGate/GateFactoryT/GateFactoryTest 的类图如下 ⬇️

image.png

运行

在项目顶层执行如下命令,可以运行单元测试

mvn clean test

运行后,会看到项目顶层多了 net 和 org 这两个目录。执行 tree net org 命令后,会看到如下结果 ⬇️

net
└── sf
    └── cglib
        ├── core
        │   └── MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7.class
        └── proxy
            └── Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72.class
org
└── example
    ├── AbstractAndGate$$EnhancerByCGLIB$$4542421f.class
    └── AbstractAndGate$$EnhancerByCGLIB$$5ca9308f.class

7 directories, 4 files

以下两个文件看起来和 AbstractAndGate 直接相关

  • AbstractAndGate$$EnhancerByCGLIB$$4542421f.class
  • AbstractAndGate$$EnhancerByCGLIB$$5ca9308f.class

我们在 Intellij IDEA (Community Edition) 可以看到这两个 class 文件反编译的结果(但完整的结果比较长,这里就不展示了)。下方是它们的类图 ⬇️

x.png

分析

我们先看 Dispatcher

Dispatcher

IntelliJ IDEA (Community Edition) 反编译的结果(如下图所示)来看,AbstractAndGate$$EnhancerByCGLIB$$5ca9308f 中的下列方法的处理逻辑类似 ⬇️

  • equals(Object)
  • hashCode()
  • toString()
  • calculate(boolean...)

这些方法在调用 loadObject() 方法后,对它的返回值的处理有些差异(我在下图中用红线把有差异的地方标出来了)。

image.png

所以我们着重看一个方法就行了。我们来看看 calculate(boolean...) 方法 ⬇️

public final boolean calculate(boolean... var1) {
    Dispatcher var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_0;
    }

    return ((AbstractAndGate)var10000.loadObject()).calculate(var1);
}

看起来主线逻辑是这样的 ⬇️

image.png

那么以下两者是否为同一个引用呢?

  • AbstractAndGate$$EnhancerByCGLIB$$5ca9308f 中的 CGLIB$CALLBACK_0 字段
  • GateFactory 中的 dispatcher 字段

我用如下的单元测试(上文已提供完整代码)验证了一下 ⬇️ 两者确实为同一个引用

image.png

那么,在代理类中使用 Dispatcher 的主线逻辑就可以这样概括了 ⬇️

image.png

我们再去看看 LazyLoader

LazyLoader

IntelliJ IDEA (Community Edition) 反编译的结果(如下图所示)来看,AbstractAndGate$$EnhancerByCGLIB$$4542421f 中的下列方法的处理逻辑类似 ⬇️

  • equals(Object)
  • hashCode()
  • toString()
  • calculate(boolean...)

image.png 这些方法内部都调用了 CGLIB$LOAD_PRIVATE_0() 方法,后者的逻辑如下 ⬇️

private final synchronized Object CGLIB$LOAD_PRIVATE_0() {
    Object var10000 = this.CGLIB$LAZY_LOADER_0;
    if (var10000 == null) {
        LazyLoader var10001 = this.CGLIB$CALLBACK_0;
        if (var10001 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10001 = this.CGLIB$CALLBACK_0;
        }

        var10000 = this.CGLIB$LAZY_LOADER_0 = var10001.loadObject();
    }

    return var10000;
}

看起来 this.CGLIB$LAZY_LOADER_0 字段的赋值处理是懒式的。假设 this.CGLIB$CALLBACK_0 字段和 org.example.GateFactory\text{org.example.GateFactory}lazyLoader\text{lazyLoader} 字段引用的是同一个对象。最初 this.CGLIB$LAZY_LOADER_0null,下图第 43 行的 if 条件成立,第 50 行会给 this.CGLIB$LAZY_LOADER_0 赋值(所赋的值是 org.example.ExpensiveAndGate\text{org.example.ExpensiveAndGate} 的一个实例)

image.png

那么之后再执行这个方法时,this.CGLIB$LAZY_LOADER_0 已经不是 null 了,下图第 43 行的 if 语句条件不成立,直接执行第 53 行。

image.png

但是假设毕竟是假设,还是要验证一下以下两者是否为同一个引用。

  • AbstractAndGate$$EnhancerByCGLIB$$4542421f 中的 CGLIB$CALLBACK_0 字段
  • GateFactory 中的 lazyLoader 字段

我用如下的单元测试(上文已提供完整代码)验证了一下 ⬇️ 两者确实为同一个引用

image.png

那么,在代理类中使用 LazyLoader 的主线逻辑就可以这样概括了 ⬇️

image.png

其他

画 "net.sf.cglib.proxy.Callback 和它的子接口" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml

title <i>net.sf.cglib.proxy.Callback</i> 和它的子接口

interface net.sf.cglib.proxy.Callback
interface net.sf.cglib.proxy.MethodInterceptor
interface net.sf.cglib.proxy.NoOp
interface net.sf.cglib.proxy.LazyLoader #lightgreen
interface net.sf.cglib.proxy.Dispatcher #lightgreen
interface net.sf.cglib.proxy.InvocationHandler
interface net.sf.cglib.proxy.FixedValue

net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.MethodInterceptor
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.NoOp
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.LazyLoader
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.Dispatcher
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.InvocationHandler
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.FixedValue

note top of net.sf.cglib.proxy.Callback
这是一个 <i>marker interface</i>
(这个接口里没有定义任何方法)
end note

note as n1
它们是本文的主角
浅绿色背景表示强调
无特殊语义
end note

net.sf.cglib.proxy.LazyLoader .. n1
net.sf.cglib.proxy.Dispatcher .. n1

@enduml

画 "net.sf.cglib.proxy.LazyLoadernet.sf.cglib.proxy.Dispatcher" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml

title <i>net.sf.cglib.proxy.LazyLoader</i> 和 <i>net.sf.cglib.proxy.Dispatcher</i>

interface net.sf.cglib.proxy.Callback
interface net.sf.cglib.proxy.LazyLoader
interface net.sf.cglib.proxy.Dispatcher

net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.LazyLoader
net.sf.cglib.proxy.Callback <|-- net.sf.cglib.proxy.Dispatcher

interface net.sf.cglib.proxy.Dispatcher {
    Object loadObject() throws Exception
}

interface net.sf.cglib.proxy.LazyLoader {
    Object loadObject() throws Exception
}

@enduml

画 "五个类的类图" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml
'https://plantuml.com/class-diagram

title 五个类的类图

abstract class org.example.AbstractAndGate {
    - void validateInputLength(boolean[])
    + boolean calculate(boolean...)
}

org.example.AbstractAndGate <|-- org.example.CheapAndGate
org.example.AbstractAndGate <|-- org.example.ExpensiveAndGate

class org.example.CheapAndGate {
    + CheapAndGate()
    + String toString()
}

class org.example.ExpensiveAndGate {
    + ExpensiveAndGate()
    + String toString()
}

class org.example.GateFactory {
    - {static} Dispatcher dispatcher
    - {static} LazyLoader lazyLoader
    + {static} AbstractAndGate buildCheapAndGate()
    + {static} AbstractAndGate buildExpensiveAndGate()
}

class org.example.GateFactoryTest {
    + void testBuildCheapAndGate()
    + void testBuildExpensiveAndGate()
    + void testDispatcher()
    + void testLazyLoader()
}

@enduml

画 "两个动态代理类的类图" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml
'https://plantuml.com/class-diagram

title 两个动态代理类的类图

abstract class org.example.AbstractAndGate {
    - void validateInputLength(boolean[])
    + boolean calculate(boolean...)
}

org.example.AbstractAndGate <|-- org.example.CheapAndGate
org.example.AbstractAndGate <|-- org.example.ExpensiveAndGate

class org.example.CheapAndGate {
    + CheapAndGate()
    + String toString()
}

class org.example.ExpensiveAndGate {
    + ExpensiveAndGate()
    + String toString()
}

interface net.sf.cglib.proxy.Factory {
    Object newInstance(Callback callback)
    Object newInstance(Callback[] callbacks)
    Object newInstance(Class[] types, Object[] args, Callback[] callbacks)
    Callback getCallback(int index)
    void setCallback(int index, Callback callback)
    void setCallbacks(Callback[] callbacks)
    Callback[] getCallbacks()
}

net.sf.cglib.proxy.Factory <|.. org.example.AbstractAndGate$$EnhancerByCGLIB$$4542421f
org.example.AbstractAndGate <|-- org.example.AbstractAndGate$$EnhancerByCGLIB$$4542421f

class org.example.AbstractAndGate$$EnhancerByCGLIB$$4542421f {
  - boolean CGLIB$BOUND
  + {static} Object CGLIB$FACTORY_DATA
  - {static} final ThreadLocal CGLIB$THREAD_CALLBACKS
  - {static} final Callback[] CGLIB$STATIC_CALLBACKS
  - LazyLoader CGLIB$CALLBACK_0
  - {static} Object CGLIB$CALLBACK_FILTER
  - Object CGLIB$LAZY_LOADER_0
  {static} void CGLIB$STATICHOOK2()
  + final boolean calculate(boolean...)
  + final boolean equals(Object)
  + final String toString()
  + final int hashCode()
  - final synchronized Object CGLIB$LOAD_PRIVATE_0()
  + org.example.AbstractAndGate$$EnhancerByCGLIB$$4542421f()
  + {static} void CGLIB$SET_THREAD_CALLBACKS(Callback[])
  + {static} void CGLIB$SET_STATIC_CALLBACKS(Callback[])
  - {static} final void CGLIB$BIND_CALLBACKS(Object)
  + Object newInstance(Callback[])
  + Object newInstance(Callback)
  + Object newInstance(Class[], Object[], Callback[])
  + Callback getCallback(int)
  + void setCallback(int, Callback)
  + Callback[] getCallbacks()
  + void setCallbacks(Callback[])
}

net.sf.cglib.proxy.Factory <|.. org.example.AbstractAndGate$$EnhancerByCGLIB$$5ca9308f
org.example.AbstractAndGate <|-- org.example.AbstractAndGate$$EnhancerByCGLIB$$5ca9308f
class org.example.AbstractAndGate$$EnhancerByCGLIB$$5ca9308f {
  - boolean CGLIB$BOUND
  + {static} Object CGLIB$FACTORY_DATA
  - {static} final ThreadLocal CGLIB$THREAD_CALLBACKS
  - {static} final Callback[] CGLIB$STATIC_CALLBACKS
  - net.sf.cglib.proxy.Dispatcher CGLIB$CALLBACK_0
  - {static} Object CGLIB$CALLBACK_FILTER
  {static} void CGLIB$STATICHOOK1()
  + final boolean calculate(boolean...)
  + final boolean equals(Object)
  + final String toString()
  + final int hashCode()
  + org.example.AbstractAndGate$$EnhancerByCGLIB$$5ca9308f()
  + {static} void CGLIB$SET_THREAD_CALLBACKS(Callback[])
  + {static} void CGLIB$SET_STATIC_CALLBACKS(Callback[])
  - {static} final void CGLIB$BIND_CALLBACKS(Object)
  + Object newInstance(Callback[])
  + Object newInstance(Callback)
  + Object newInstance(Class[], Object[], Callback[])
  + Callback getCallback(int)
  + void setCallback(int, Callback)
  + Callback[] getCallbacks()
  + void setCallbacks(Callback[])
}

@enduml

画 "在代理类中使用 Dispatcher 的主线逻辑" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startwbs
caption \n\n
' caption 的内容是为了防止掘金平台生成的水印遮盖图中的文字

* 在代理类中使用 <i>net.sf.cglib.proxy.Dispatcher</i> 的主线逻辑
**:将 <i>this.CGLIB$CALLBACK_0</i> 保存在局部变量 <b><i>var10000</i></b> 中
(两者的类型都是 <b><i>net.sf.cglib.proxy.Dispatcher</i></b>);
***_:可以简单认为以下两者引用的是同一个对象
<&star> <i>this.CGLIB$CALLBACK_0</i>
<&star> <i>org.example.GateFactory</i> 中的 <b><i>dispatcher</i></b> 字段;
**:调用 <b><i>var10000.loadObject()</i><b> 方法,
并将返回值转化为 <i>AbstractAndGate</i> 类型
(我们将转化后的值简称为 <b><i>aag</i><b>);
***_:每次调用 <b><i>var10000.loadObject()</i><b> 方法时,
都会生成一个新的
<i>org.example.CheapAndGate</i> 实例;
**:执行 <i><b>aag</b>.calculate(var1)</i>,
并将它的返回值作为当前方法的返回值;
@endwbs

画 "在代理类中使用 net.sf.cglib.proxy.LazyLoader 的主线逻辑" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startwbs
caption \n\n
' caption 的内容是为了防止掘金平台生成的水印遮盖图中的文字

* 在代理类中使用 <i>net.sf.cglib.proxy.LazyLoader</i> 的主线逻辑
**:调用 <b><i>CGLIB$LOAD_PRIVATE_0()</i></b> 方法,
获取 <b><i>org.example.ExpensiveAndGate</i></b> 的实例 <b><i>eag</i></b>;
***:如果 <b><i>this.CGLIB$LAZY_LOADER_0</i></b> 是 <i>null</i>
则执行 <b><i>this.CGLIB$CALLBACK_0.loadObject()</i></b>
(会得到一个 <b><i>org.example.ExpensiveAndGate</i></b> 实例),
并将结果赋值给 <b><i>this.CGLIB$LAZY_LOADER_0</i></b>;
*** 返回 <b><i>this.CGLIB$LAZY_LOADER_0</i></b>
**:执行 <i><b>eag</b>.calculate(var1)</i>
并将它的返回值作为当前方法的返回值;
@endwbs

画 "要点(Dispatcher 部分)" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml

title 要点(<i>Dispatcher</i> 部分)
caption \n\n
' caption 中的内容只是为了防止掘金平台的水印遮盖图中的文字

interface Callback
interface Dispatcher

Callback <|-- Dispatcher

interface Dispatcher {
    Object loadObject() throws Exception
}

class SomeClass {
    + void someMethod()
}

class SomeDispatcher {
    + Object loadObject() throws Exception
}

Dispatcher <|.. SomeDispatcher

class "Proxy<sub>SomeClass</sub>" as P

class P {
    - Dispatcher CGLIB$CALLBACK_0
    + final void someMethod()
}

SomeClass <|-- P

note as n1
通过如下代码可以生成 SomeClass 的动态代理类: Proxy<sub>SomeClass</sub>
<code>
(SomeClass) Enhancer.create(SomeClass.class, new SomeDispatcher());
</code>
end note

SomeClass <.. n1: 用户指定的类 SomeClass
n1 ..> P: 生成的动态代理类 Proxy<sub>SomeClass</sub>

note right of SomeDispatcher
用户提供的 <i>Dispatcher</i> 的实现类
end note

P::CGLIB$CALLBACK_0 ..> SomeDispatcher : 该字段持有一个 SomeDispatcher 的实例

header
这张图里是以 <b>类</b> 为例, 描述了相关的要点
如果用户指定的是某个 <b>接口</b> <i>SomeInterface</i>, 那么 <i>cglib</i> 也可以用类似的方式进行处理
end header

note left of P::someMethod
可以认为它的代码是这样的 <:point_down:> (可以先忽略其中的 if 语句块)

<code>
public final void someMethod() {
    Dispatcher var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_0;
    }

    ((SomeClass)var10000.loadObject()).someMethod();
}
</code>
end note

@enduml

画 "要点(LazyLoader 部分)" 用到的代码

我用了 PlantUML 的插件来画那张图,所用到的代码如下 ⬇️

@startuml

title 要点(<i>LazyLoader</i> 部分)
caption \n\n
' caption 中的内容只是为了防止掘金平台的水印遮盖图中的文字

interface Callback
interface LazyLoader

Callback <|-- LazyLoader

interface LazyLoader {
    Object loadObject() throws Exception
}

class SomeClass {
    + void someMethod()
}

class SomeLazyLoader {
    + Object loadObject() throws Exception
}

LazyLoader <|.. SomeLazyLoader

class "Proxy<sub>SomeClass</sub>" as P

class P {
    - LazyLoader CGLIB$CALLBACK_0
    - Object CGLIB$LAZY_LOADER_0
    + final void someMethod()
    - final synchronized Object CGLIB$LOAD_PRIVATE_0()
}

SomeClass <|-- P

note as n1
通过如下代码可以生成 SomeClass 的动态代理类: Proxy<sub>SomeClass</sub>
<code>
(SomeClass) Enhancer.create(SomeClass.class, new SomeLazyLoader());
</code>
end note

SomeClass <.. n1: 用户指定的类 SomeClass
n1 ..> P: 生成的动态代理类 Proxy<sub>SomeClass</sub>

note right of SomeLazyLoader
用户提供的 <i>LazyLoader</i> 的实现类
end note

P::CGLIB$CALLBACK_0 ..> SomeLazyLoader : 该字段持有一个 SomeLazyLoader 的实例

header
这张图里是以 <b>类</b> 为例, 描述了相关的要点
如果用户指定的是某个 <b>接口</b> <i>SomeInterface</i>, 那么 <i>cglib</i> 也可以用类似的方式进行处理
end header

note left of P::CGLIB$LAZY_LOADER_0
这个字段用 lazy 的方式,
保存 <i>SomeLazyLoader.loadObject()</i> 的返回值
end note

note left of P::someMethod
可以认为它的代码是这样的 <:point_down:>

<code>
public final void someMethod() {
    ((SomeClass)this.CGLIB$LOAD_PRIVATE_0()).someMethod();
}
</code>
end note

note left of P::CGLIB$LOAD_PRIVATE_0
可以认为它的代码是这样的 <:point_down:>

<code>
private final synchronized Object CGLIB$LOAD_PRIVATE_0() {
    Object var10000 = this.CGLIB$LAZY_LOADER_0;
    if (var10000 == null) {
        LazyLoader var10001 = this.CGLIB$CALLBACK_0;
        ... // 为了简化主线逻辑, 我在这个地方省略了一个 if 语句块

        var10000 = this.CGLIB$LAZY_LOADER_0 = var10001.loadObject();
    }

    return var10000;
}
</code>
end note

@enduml