目录
  1. 1. 一、cglib 是什么
  2. 2. 二、JDK 动态代理 vs cglib 动态代理
    1. 2.1. 2.1 JDK 动态代理
    2. 2.2. 2.2 cglib 动态代理
    3. 2.3. 2.3 特性对比表
  3. 3. 三、Enhancer 的工作原理
    1. 3.1. 3.1 Enhancer 的核心流程
    2. 3.2. 3.2 生成的代理类字节码结构
    3. 3.3. 3.3 MethodProxy 与 FastClass 机制
  4. 4. 四、cglib 的局限性
    1. 4.1. 4.1 final 限制
    2. 4.2. 4.2 构造函数限制
    3. 4.3. 4.3 内部调用问题
    4. 4.4. 4.4 包名和类名冲突
    5. 4.5. 4.5 equals/hashCode/toString 的默认行为
  5. 5. 五、cglib 的其他拦截器类型
    1. 5.1. 5.1 CallbackFilter —— 按方法名选择不同的拦截策略
    2. 5.2. 5.2 LazyLoader —— 延迟加载
    3. 5.3. 5.3 Dispatcher —— 每次调用都重新分发
    4. 5.4. 5.4 BeanCopier —— 对象属性拷贝
  6. 6. 六、Spring AOP 中的 cglib
    1. 6.1. 6.1 Spring 如何选择代理方式
    2. 6.2. 6.2 Spring 对 cglib 的优化
  7. 7. 七、Android 平台的动态代理替代方案
    1. 7.1. 7.1 JDK 动态代理
    2. 7.2. 7.2 DexMaker
    3. 7.3. 7.3 编译期代码生成(推荐方式)
  8. 8. 八、cglib 相关源码路径
  9. 9. 九、常见面试题
【深入理解JVM字节码】第十二篇、cglib动态代理原理

一、cglib 是什么

cglib(Code Generation Library)是一个强大的字节码生成库,它基于 ASM 实现,能够在运行时动态生成 Java 类的子类。与 JDK 自带的动态代理(java.lang.reflect.Proxy)不同,cglib 不要求目标类必须实现接口——它通过生成目标类的子类来实现代理,这使得它可以代理任何非 final 的类。

cglib 在 Java 后端生态中占据核心地位。Spring AOP 在目标类没有实现接口时,默认使用 cglib 来创建代理对象;Hibernate 使用 cglib 来实现延迟加载(lazy loading)的代理;Mockito 在早期版本也使用 cglib 来创建 mock 对象。

cglib 的核心类包括:

  • net.sf.cglib.proxy.Enhancer:代理对象的创建器
  • net.sf.cglib.proxy.MethodInterceptor:方法拦截器接口
  • net.sf.cglib.proxy.Callback:所有拦截器的基接口
  • net.sf.cglib.proxy.FixedValue:返回值固定的拦截器
  • net.sf.cglib.proxy.NoOp:不做任何拦截,直接调用父类方法
  • net.sf.cglib.proxy.LazyLoader:延迟加载拦截器
  • net.sf.cglib.reflect.FastClass:FastClass 机制,绕过反射提高调用性能

二、JDK 动态代理 vs cglib 动态代理

这是面试中的经典对比问题。两者的本质区别如下:

2.1 JDK 动态代理

JDK 动态代理基于接口(interface-based),通过 java.lang.reflect.ProxyInvocationHandler 实现。

// 目标接口
public interface UserService {
void save(String name);
}

// 目标实现
public class UserServiceImpl implements UserService {
public void save(String name) {
System.out.println("Saving: " + name);
}
}

// JDK 动态代理
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class<?>[]{UserService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Before: " + method.getName());
Object result = method.invoke(target, args); // 反射调用
System.out.println("After: " + method.getName());
return result;
}
}
);

JDK 动态代理的核心限制:只能代理实现了接口的类

在字节码层面,JDK 动态代理生成的代理类($Proxy0)直接继承 java.lang.reflect.Proxy,而 Java 是单继承的,因此代理类无法再继承其他具体的类——只能实现目标接口。

2.2 cglib 动态代理

cglib 通过生成目标类的子类来实现代理(subclass-based):

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 目标类(无需实现任何接口)
public class UserService {
public void save(String name) {
System.out.println("Saving: " + name);
}

public final String findById(Long id) {
return "User-" + id; // final 方法无法被代理
}
}

// cglib 代理
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class); // 设置目标类为父类
enhancer.setCallback(new MethodInterceptor() { // 设置拦截器
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("Before: " + method.getName());
// 方式一:通过 proxy.invokeSuper 调用父类方法(推荐,FastClass 机制)
Object result = proxy.invokeSuper(obj, args);
// 方式二:通过 method.invoke 反射调用(慢)
// Object result = method.invoke(obj, args);
System.out.println("After: " + method.getName());
return result;
}
});

UserService proxy = (UserService) enhancer.create();
proxy.save("张三"); // 触发了拦截器

2.3 特性对比表

维度 JDK 动态代理 cglib 动态代理
代理方式 基于接口 基于子类继承
目标类要求 必须实现至少一个接口 不能是 final 类
方法要求 接口中定义的方法 不能是 final/static 方法
生成的是 Proxy 的子类 + 接口实现 目标类的子类
内部调用 不会触发代理(调的是原始对象) 不会触发代理(调的是父类方法)
性能(创建) 快(只生成一个类) 慢(生成子类 + FastClass,字节码量大)
性能(调用) 慢(反射 invoke) 快(FastClass 索引访问)
依赖 JDK 内置 需引入 cglib(或 spring-core 自带的 repackaged 版本)

三、Enhancer 的工作原理

3.1 Enhancer 的核心流程

Enhancer 是 cglib 创建代理对象的入口。其工作流程分为以下步骤:

1. setSuperclass(targetClass)     → 设置目标类为生成的代理类的父类
2. setCallback(callback) → 设置方法拦截器
3. create() → 触发生成和实例化
├── 3.1 生成代理类名(如 UserService$$EnhancerByCGLIB$$12345)
├── 3.2 使用 ASM 生成代理类的字节码
│ ├── 生成与目标类相同的构造函数
│ ├── 为每个非 final 方法生成重写版本
│ ├── 在重写方法中植入拦截器调用逻辑
│ └── 生成 CGLIB$ 前缀的内部辅助方法
├── 3.3 通过 ClassLoader 加载代理类
├── 3.4 生成对应的 FastClass(UserService$$FastClassByCGLIB$$...)
└── 3.5 通过反射调用代理类的构造方法创建实例

3.2 生成的代理类字节码结构

假设目标类如下:

public class Calculator {
public int add(int a, int b) {
return a + b;
}
}

cglib 生成的代理类结构(反编译后的近似代码):

public class Calculator$$EnhancerByCGLIB$$12345 extends Calculator 
implements Factory {

private MethodInterceptor CGLIB$CALLBACK_0;

// 原始方法的一个"镜像"方法,用于 proxy.invokeSuper 调用
final int CGLIB$add$0(int a, int b) {
return super.add(a, b);
}

// 重写的方法——这是拦截发生的入口
@Override
public final int add(int a, int b) {
MethodInterceptor interceptor = CGLIB$CALLBACK_0;
if (interceptor != null) {
// 调用拦截器的 intercept 方法
return (Integer) interceptor.intercept(
this,
CGLIB$add$0$Method, // 缓存的 Method 对象
new Object[]{a, b}, // 参数数组
CGLIB$add$0$Proxy // MethodProxy 对象
);
}
return super.add(a, b);
}

// 静态块中初始化 Method 和 MethodProxy 对象
static {
CGLIB$STATICHOOK1();
}
}

关键观察

  1. 代理类继承目标类,因此所有非 final 的 public/protected 方法都会被重写
  2. 每个方法生成一个 CGLIB$ 前缀的镜像方法,该镜像方法直接调用父类(即目标类)的对应方法(使用 super.xxx()
  3. 重写方法被声明为 final,以防止代理类的子类再次重写导致无限循环
  4. MethodProxy 是关键,它包装了 FastClass 机制,使得 proxy.invokeSuper() 能够快速调用到镜像方法

3.3 MethodProxy 与 FastClass 机制

cglib 最精妙的设计之一就是 FastClass 机制。传统 JDK 动态代理中,每次方法调用都需要 method.invoke(target, args)——这是 Java 反射调用,性能较差。cglib 通过 FastClass 机制绕过了反射。

FastClass 的核心思想:为每个类生成一个索引表,将方法名映射为整数索引,然后通过 switch-case 进行方法分发

FastClass 的生成逻辑(简化版):

// 为 Calculator 类生成的 FastClass
public class Calculator$$FastClassByCGLIB$$67890 extends FastClass {

@Override
public int getIndex(String name, Class[] parameterTypes) {
switch(name) {
case "add":
if (parameterTypes.length == 2
&& parameterTypes[0] == Integer.TYPE
&& parameterTypes[1] == Integer.TYPE) {
return 0; // add(int, int) 的索引为 0
}
break;
case "equals":
// ...
}
return -1;
}

@Override
public Object invoke(int index, Object obj, Object[] args)
throws InvocationTargetException {
Calculator calc = (Calculator) obj;
switch(index) {
case 0:
return calc.add((Integer) args[0], (Integer) args[1]);
case 1:
return calc.equals(args[0]);
// ...
}
throw new IllegalArgumentException("Unknown index: " + index);
}
}

MethodProxy 的 invokeSuper 方法的底层实现:

// MethodProxy.java (简化逻辑)
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init(); // 延迟初始化 FastClass 信息
FastClassInfo fci = fastClassInfo;
// fci.f1: 目标类的 FastClass
// fci.f2: 代理类的 FastClass
// fci.i2: 方法在代理类中的索引(对应 CGLIB$add$0)
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}

调用链路总结

proxy.add(1, 2)
→ Calculator$$EnhancerByCGLIB$$12345.add(1, 2) [重写的方法]
→ MethodInterceptor.intercept(...)
→ proxy.invokeSuper(obj, args)
→ FastClass.invoke(i2, obj, args)
→ switch(i2) case 0: return obj.CGLIB$add$0(1, 2)
→ super.add(1, 2) [调用目标类的方法]

四、cglib 的局限性

4.1 final 限制

cglib 的第一个重大限制:无法代理 final 类。因为 Java 不允许继承 final 类。

public final class ImmutableService { ... }
// Enhancer.create(ImmutableService.class)
// → 抛出 IllegalArgumentException: Cannot subclass final class

同样,final 方法也无法被代理。cglib 通过子类重写方法来实现拦截,而 final 方法不能被重写:

public class BaseService {
public final void criticalOperation() {
// 此方法永远不会被 cglib 拦截
}
}

Spring AOP 的应对策略:Spring AOP 默认使用 JDK 动态代理(接口模式),当没有接口时才回退到 cglib。从 Spring Boot 2.0 开始,spring.aop.proxy-target-class 默认为 true,即默认使用 cglib。如果目标方法是 final 的,Spring 会打印警告日志并跳过该方法的代理。

4.2 构造函数限制

cglib 生成的代理类会调用父类的构造方法。如果目标类没有无参构造方法,你需要显式传递参数:

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(NoDefaultConstructor.class);
enhancer.setCallback(callback);
// 通过参数类型和值指定要调用的构造方法
NoDefaultConstructor proxy = (NoDefaultConstructor) enhancer.create(
new Class[]{String.class},
new Object[]{"parameter"}
);

特别提醒:cglib 创建代理对象时会调用两次构造方法——一次是 Enhancer.create() 直接调用代理类的构造方法,另一次是代理类的构造方法内部调用父类(目标类)的构造方法。因此,不要在构造方法中执行有副作用的逻辑(如开启数据库连接、启动线程等),否则这些逻辑会被执行多次。

4.3 内部调用问题

与 JDK 动态代理一样,cglib 也无法拦截目标类内部的方法调用(self-invocation):

public class OrderService {
public void checkout() {
// 这是一个内部调用,不会触发代理
this.validate(); // 这里的 this 是代理对象
processPayment();
}

public void validate() {
// 如果在外部直接调用 proxy.validate(),会触发拦截
// 但在 checkout() 内部调用时,this.validate() 实际调用的是
// 代理类的父类方法,不会经过重写的方法
}
}

解决方案:使用 AopContext.currentProxy() 获取当前代理对象(Spring 中需要 @EnableAspectJAutoProxy(exposeProxy = true)),或者将内部调用的方法提取到另一个 Bean 中。

4.4 包名和类名冲突

cglib 生成的代理类名为 目标类名$$EnhancerByCGLIB$$随机数。这些类存在于 JVM 的 Metaspace 中。在大量创建代理类的场景下(如 Spring 应用中每个原型 Bean 都会生成一个代理类),需要注意:

  • 代理类的数量可能导致 Metaspace 溢出(OutOfMemoryError: Metaspace
  • 频繁创建代理类会产生大量的类加载开销

4.5 equals/hashCode/toString 的默认行为

cglib 默认不会拦截 equals()hashCode()toString() 方法。这三个方法的默认行为继承自 java.lang.Object。如果需要拦截它们,需要设置不同的 CallbackFilter。

五、cglib 的其他拦截器类型

5.1 CallbackFilter —— 按方法名选择不同的拦截策略

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallbacks(new Callback[]{
new MethodInterceptor() { ... }, // 索引 0:业务方法拦截器
NoOp.INSTANCE, // 索引 1:不做任何拦截
new FixedValue() { // 索引 2:固定返回值
public Object loadObject() { return "CACHED"; }
}
});
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
if (method.getName().startsWith("get")) {
return 2; // getter 方法返回固定值
}
if (method.getDeclaringClass() == Object.class) {
return 1; // Object 的方法不拦截
}
return 0; // 其他方法使用业务拦截器
}
});

5.2 LazyLoader —— 延迟加载

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(HeavyService.class);
enhancer.setCallback(new LazyLoader() {
@Override
public Object loadObject() throws Exception {
// 只有在第一次访问代理对象的方法时,才会创建真实对象
System.out.println("Creating heavy service...");
return new HeavyService();
}
});

// 此时 HeavyService 并没有被创建
HeavyService proxy = (HeavyService) enhancer.create();
// 第一次方法调用时,才触发 loadObject() 创建真实对象
proxy.doWork();

Hibernate 的延迟加载就是基于同样的原理:代理对象持有对真实对象的引用,只有当真正访问数据时才触发 SQL 查询。

5.3 Dispatcher —— 每次调用都重新分发

与 LazyLoader 类似,但 Dispatcher 的 loadObject() 在每次方法调用时都会被调用:

enhancer.setCallback(new Dispatcher() {
@Override
public Object loadObject() {
// 每次方法调用都返回一个新的目标对象
return applicationContext.getBean(SomeService.class);
}
});

5.4 BeanCopier —— 对象属性拷贝

cglib 还提供了基于字节码生成的高性能 Bean 属性拷贝工具:

BeanCopier copier = BeanCopier.create(Source.class, Target.class, false);
Target target = new Target();
copier.copy(source, target, null); // 比 BeanUtils.copyProperties 快 10+ 倍

六、Spring AOP 中的 cglib

6.1 Spring 如何选择代理方式

Spring AOP 的核心代理创建逻辑在 org.springframework.aop.framework.DefaultAopProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory {
@Override
public AopProxy createAopProxy(AdvisedSupport config) {
if (config.isOptimize() || config.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 使用 cglib 代理(Spring 内部重新打包了 cglib)
return new ObjenesisCglibAopProxy(config);
} else {
return new JdkDynamicAopProxy(config);
}
}
}

Spring 的判断逻辑:

  1. 如果目标类实现了接口且 proxyTargetClass 为 false → JDK 动态代理
  2. 如果目标类没有实现接口 → cglib(ObjenesisCglibAopProxy)
  3. 如果 proxyTargetClass 为 true → cglib

6.2 Spring 对 cglib 的优化

Spring 不是直接使用原始 cglib,而是对其进行了封装和优化:

  • ObjenesisCglibAopProxy:Spring 使用 Objenesis 库来绕过构造方法调用,避免 cglib 创建代理时调用两次构造方法的问题。
  • Spring 4.0+ 内嵌 cglib:从 Spring 3.2 开始,cglib 的代码被重新打包到 spring-coreorg.springframework.cglib 包下,不再需要外部依赖。
  • @Configuration 代理:Spring 使用 cglib 代理 @Configuration 类,确保 @Bean 方法的单例语义(防止同一个 @Bean 方法被多次调用时创建多个实例)。

七、Android 平台的动态代理替代方案

Android 上不能直接使用 cglib(因为 cglib 依赖 JVM 的类加载机制和 sun.misc.Unsafe,这在 ART 上不可用)。Android 平台有几种替代方案:

7.1 JDK 动态代理

Android 支持 java.lang.reflect.Proxy,但同样只能代理接口。这是 Android 上最常用且可靠的方式:

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.build();

// Retrofit.create() 内部使用 JDK 动态代理
ApiService api = retrofit.create(ApiService.class);

Retrofit 通过 JDK 动态代理将接口方法调用转换为 HTTP 请求,这是 Android 上最经典的动态代理应用。

7.2 DexMaker

DexMaker 是 LinkedIn 开发的一个用于在 Android 运行时生成 DEX 代码的库,类似于 cglib 在 JVM 上的作用。它可以动态生成 DEX 字节码并加载到当前 ClassLoader 中。

// DexMaker 使用示例(类似 cglib 的 Enhancer)

Mockito 在 Android 上的早期版本就使用了 DexMaker 来生成 mock 对象的 DEX 代码。

7.3 编译期代码生成(推荐方式)

相比运行时动态代理,Android 生态更推荐在编译期通过 APT 或 Gradle Transform 来生成代码。这种方式不依赖运行时的类加载机制,且性能更好:

  • Dagger2:使用 APT 在编译期生成依赖注入代码
  • Room:使用 APT 生成数据库访问代码
  • DataBinding:使用 APT 生成绑定代码
  • 自定义 Gradle Plugin + ASM:在 Transform 阶段修改字节码

八、cglib 相关源码路径

组件 源码路径
cglib Enhancer cglib/cglib/src/main/java/net/sf/cglib/proxy/Enhancer.java
cglib FastClass cglib/cglib/src/main/java/net/sf/cglib/reflect/FastClass.java
cglib MethodProxy cglib/cglib/src/main/java/net/sf/cglib/proxy/MethodProxy.java
cglib KeyFactory cglib/cglib/src/main/java/net/sf/cglib/core/KeyFactory.java
Spring AOP cglib spring-framework/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java
Spring ObjenesisCglibAopProxy spring-framework/spring-aop/src/main/java/org/springframework/aop/framework/ObjenesisCglibAopProxy.java
JDK Proxy jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java
ASM (cglib 的底层) asm/asm/src/main/java/org/objectweb/asm/ClassWriter.java

九、常见面试题

Q1: cglib 如何实现方法拦截?生成的代理类与目标类是什么关系?

A: cglib 通过生成目标类的子类来实现方法拦截。生成的代理类继承目标类,重写所有非 final、非 static 的方法。在每个重写方法中,cglib 不直接调用父类方法,而是先检查是否设置了 MethodInterceptor 回调,如果设置了,就调用 interceptor.intercept() 方法,将控制权交给开发者;如果没有设置,才直接调用父类方法。代理类还会为每个被重写的方法生成一个 CGLIB$ 前缀的”镜像方法”,该方法内部直接调用 super.xxx()——这保证了在 MethodInterceptor 中可以通过 proxy.invokeSuper() 获取到原始方法的调用。这种设计实现了”拦截器模式”,将方法调用的控制权完全交给开发者。

Q2: MethodProxy.invokeSuper() 和 Method.invoke() 在 cglib 中的区别是什么?为什么前者更快?

A: 两者的核心区别在于调用方式。Method.invoke(obj, args) 是标准的 Java 反射调用,每次调用都需要经过访问权限检查、参数包装(自动装箱拆箱)、以及 JVM 内部的 native 方法调用(NativeMethodAccessorImpl.invoke0),这些开销很大。而 MethodProxy.invokeSuper(obj, args) 使用的是 cglib 的 FastClass 机制:FastClass 为每个类生成了一个 int-to-method 的映射表,通过 switch-case 直接调用目标方法——这本质上是普通的 Java 方法调用,没有任何反射开销。FastClass 的索引通过方法签名(方法名 + 参数类型列表)的哈希来计算,第一次调用时会缓存索引,后续调用直接使用缓存。根据 cglib 的文档,FastClass 比反射调用快约 10-20 倍。

Q3: 为什么 cglib 不能代理 final 方法和 final 类?在 Spring 中如何应对这种情况?

A: cglib 通过生成子类来工作,这是根本原因。Java 规范不允许任何类继承 final 类,也不允许子类重写 final 方法——这是 JVM 在类加载验证阶段就强制实施的约束(定义在 JVM 规范 4.10 节)。Spring AOP 面对这种情况时有两种策略:(1) 如果目标类实现了接口,Spring 会优先使用 JDK 动态代理(即使 proxyTargetClass=true 也无法绕过 final 限制);(2) 如果目标方法被标记为 final,Spring 会在日志中输出警告(如 “Unable to proxy method [finalMethod] because it is final”),并且该 final 方法不会被切面拦截,而其他非 final 方法正常被代理。从设计角度来看,如果你打算使用 AOP,应该避免将业务方法声明为 final。

Q4: cglib 创建代理时调用了几次构造方法?可能导致什么问题?如何解决?

A: cglib 创建代理对象时,实际上调用了 2 次构造方法:(1) 代理类的构造方法(由 Enhancer.create() 通过反射调用);(2) 代理类构造方法内部通过 super() 调用的目标类构造方法。如果目标类的构造方法中包含有副作用的代码(如连接数据库、注册监听器、启动线程、修改静态变量等),这些副作用会被执行两次——一次是实际的目标类实例创建时,另一次是 cglib 创建代理类的过程中。Spring 通过使用 Objenesis 库解决了这个问题:Objenesis 可以不经过构造方法(bypass constructor)直接实例化对象,从而避免了第二次构造方法调用。这就是为什么 Spring 的 cglib 代理使用的是 ObjenesisCglibAopProxy 而非原始的 CglibAopProxy

Q5: 在什么情况下 JDK 动态代理比 cglib 更好?什么情况下反过来?

A: 选择策略如下。(1) 使用 JDK 动态代理的场景:目标类有清晰的接口定义;接口方法数量较稳定(不会频繁增删);希望减少依赖(JDK 内置);不希望引入额外的字节码生成开销(Metaspace 占用)。(2) 使用 cglib 的场景:目标类没有实现接口(如一些遗留代码);需要代理类中的具体方法(如 protected 方法);需要更高的调用性能(FastClass 机制)。(3) 在 Spring 应用中,遵循默认行为即可:默认先尝试 JDK 动态代理,无法满足时回退到 cglib。从 Spring Boot 2.0 开始,proxy-target-class 默认为 true,意味着默认使用 cglib。(4) 在性能敏感的场景中,如果代理创建不是瓶颈但方法调用频率极高,cglib 的 FastClass 有明显优势;如果代理创建频繁(如大量原型 Bean),JDK 动态代理的创建成本更低。

Q6: Android 上为什么不能使用 cglib?有哪些替代方案?

A: Android 不能使用 cglib 的原因是多方面的。(1) 字节码格式不同:cglib 生成的是 JVM .class 文件,而 Android 使用的是 DEX 格式。(2) 类加载机制不同:cglib 依赖 ClassLoader.defineClass() 来动态加载生成的类,而 ART/Dalvik 使用 DexClassLoader,不兼容 JVM 的类定义方式。(3) cglib 内部使用了 sun.misc.Unsafe 和一些 JVM 专有的内部 API,这些在 ART 上不存在或被严格限制。(4) 安全限制:Android 不允许应用动态生成可执行的 DEX 代码并加载(除非使用 DexMaker,且有相应的权限和限制)。Android 上的替代方案包括:(a) JDK 动态代理(java.lang.reflect.Proxy),用于接口代理,如 Retrofit;(b) 编译期代码生成(APT、KSP),如 Dagger2、Room;(c) DexMaker,用于测试中的 mock 对象;(d) Gradle Transform + ASM,在编译阶段修改字节码。


参考文档:

打赏
  • 微信
  • 支付宝

评论