动态代理深度解析:JDK与CGLIB底层实现与实战
文章标签: #java #动态代理 #jdk-proxy #cglib #aop #字节码 #反射 #面试
目录
- 引言:动态代理的技术本质
- 理论基础:代理模式的分类与演进
- 底层原理:JVM层面的字节码生成与加载机制
- 源码深度分析:JDK动态代理核心源码逐行解读
- 源码深度分析:CGLIB动态代理核心源码逐行解读
- 实战案例:完整可运行的JDK动态代理
- 实战案例:完整可运行的CGLIB动态代理
- 实战案例:基于动态代理的迷你AOP框架
- [对比分析:JDK动态代理 vs CGLIB vs AspectJ vs Javassist](#对比分析:JDK动态代理 vs CGLIB vs AspectJ vs Javassist "#%E5%AF%B9%E6%AF%94%E5%88%86%E6%9E%90jdk%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86-vs-cglib-vs-aspectj-vs-javassist")
- 性能分析:Benchmark数据与复杂度分析
- 常见陷阱与最佳实践
- 面试题与参考答案
- 小结
引言:动态代理的技术本质
动态代理(Dynamic Proxy)不是简单的"设计模式应用",而是Java运行时字节码工程 的核心技术。它是Spring AOP、MyBatis Mapper接口、Dubbo RPC、Hibernate延迟加载等主流框架的底层基础设施。
核心认知
arduino
动态代理的技术本质:
┌─────────────────────────────────────────┐
│ 编译时静态结构 │
│ 目标类 ←── 编译 ──→ 目标字节码 │
│ ↑ │
│ └────── 代理类(编译时未知) │
│ ↓ │
│ 运行时动态生成 │
│ 代理字节码 ←── ProxyGenerator/ASM ──→ 代理类 │
│ ↑ │
│ └────── ClassLoader.defineClass() │
└─────────────────────────────────────────┘
关键洞察:代理类在源码中不存在,在运行时通过字节码技术"凭空创造"
理解动态代理需要掌握三个核心问题:
- 代理类是如何生成的? ------ 字节码生成技术(ProxyGenerator / ASM)
- 方法调用是如何被拦截的? ------ 调用转发机制(InvocationHandler / MethodInterceptor)
- 调用目标方法时的性能损耗在哪? ------ 反射调用 vs FastClass索引调用
为什么需要动态代理?
markdown
软件开发中的横切关注点(Cross-cutting Concerns):
业务代码: 代理增强后:
┌──────────┐ ┌──────────────┐
│ 核心业务 │ │ 日志记录 │
│ 订单创建 │ → │ 权限校验 │
│ 用户查询 │ │ 核心业务 │
│ 支付处理 │ │ 事务管理 │
└──────────┘ │ 性能监控 │
└──────────────┘
核心价值:不修改目标类源码,动态织入横切逻辑
理论基础:代理模式的分类与演进
1. 代理模式的本质
代理模式(Proxy Pattern)是结构型设计模式 。核心思想:为其他对象提供一种代理以控制对这个对象的访问。
scss
代理模式的UML结构:
┌──────────────┐ ┌──────────────┐
│ Subject │◄────────│ RealSubject │
│ (目标接口) │ │ (目标实现) │
└──────┬───────┘ └──────────────┘
▲
│
┌──────┴───────┐
│ Proxy │
│ (代理类) │
│ │
│ - realSubject│
│ + request() │───► preProcess()
│ │ realSubject.request()
│ │ postProcess()
└──────────────┘
2. 代理模式的演进路线
objectivec
代理模式演进时间线:
阶段1:静态代理(编译时确定)
├─ 手动编写代理类
├─ 优点:简单直观
└─ 缺点:每个目标类都需要一个代理类,代码冗余
阶段2:JDK动态代理(运行时生成接口实现)
├─ 基于接口
├─ 使用反射调用
└─ 适用:目标类实现了接口
阶段3:CGLIB动态代理(运行时生成子类)
├─ 基于继承
├─ FastClass索引调用
└─ 适用:目标类无接口
阶段4:字节码织入(编译期/加载期增强)
├─ AspectJ编译时织入
├─ Instrumentation加载时织入
└─ 适用:追求极致性能,无代理开销
3. 静态代理示例
java
// 目标接口
public interface UserService {
void saveUser(String name);
}
// 目标实现
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String name) {
System.out.println("保存用户: " + name);
}
}
// 静态代理类(编译时手写)
public class UserServiceProxy implements UserService {
private final UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void saveUser(String name) {
System.out.println("[日志] 开始保存用户: " + name);
long start = System.currentTimeMillis();
target.saveUser(name); // 调用目标方法
long cost = System.currentTimeMillis() - start;
System.out.println("[日志] 保存完成,耗时: " + cost + "ms");
}
}
静态代理的致命缺陷:
- 每个接口都需要手写代理类
- 接口方法变更时,代理类必须同步修改
- 无法复用,维护成本高
底层原理:JVM层面的字节码生成与加载机制
1. JVM类加载机制回顾
scss
类加载器的双亲委派模型:
┌─────────────────┐
│ Bootstrap │ ← 加载核心类(rt.jar)
│ ClassLoader │
└────────┬────────┘
│ 委派
┌────────▼────────┐
│ Extension │ ← 加载扩展类(ext/目录)
│ ClassLoader │
└────────┬────────┘
│ 委派
┌────────▼────────┐
│ Application │ ← 加载用户类(classpath)
│ ClassLoader │
└────────┬────────┘
│ 委派
┌────────▼────────┐
│ Custom │ ← 自定义类加载器
│ ClassLoader │
└─────────────────┘
动态代理的特殊性:
代理类需要实现用户接口,但接口由AppClassLoader加载
代理类由defineClass0()定义,需要与接口类加载器兼容
2. JDK动态代理的字节码生成原理
JDK动态代理通过sun.misc.ProxyGenerator生成字节码:
typescript
字节码生成流程:
Proxy.newProxyInstance()
│
▼
getProxyClass0(loader, interfaces)
│
▼
ProxyClassFactory.apply()
│
├── 1. 生成代理类名:com.sun.proxy.$Proxy0
├── 2. ProxyGenerator.generateProxyClass()
│ │
│ ├── 生成类头(ACC_PUBLIC | ACC_FINAL)
│ ├── 生成字段:private static Method m0, m1, m2...
│ ├── 生成静态代码块:初始化Method对象
│ ├── 生成构造器:public $Proxy0(InvocationHandler)
│ └── 生成方法体:super.h.invoke(this, mX, args)
│
└── 3. Unsafe.defineClass0() 加载到JVM
生成的$Proxy0类结构:
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1; // equals方法
private static Method m2; // hashCode方法
private static Method m3; // UserService.saveUser方法
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("UserService").getMethod("saveUser",
Class.forName("java.lang.String"));
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
public $Proxy0(InvocationHandler h) {
super(h);
}
public final void saveUser(String name) {
try {
super.h.invoke(this, m3, new Object[]{name});
} catch (Error | RuntimeException e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
public final boolean equals(Object obj) {
try {
return (Boolean) super.h.invoke(this, m1, new Object[]{obj});
} catch (...) { ... }
}
// hashCode()、toString() 类似...
}
关键机制:
- 所有方法都转发到
InvocationHandler.invoke() - 方法对象(
Method)在静态代码块中初始化,避免每次调用反射查找 - 代理类被声明为
final,防止被进一步继承
3. CGLIB的字节码生成原理
CGLIB(Code Generation Library)基于ASM框架直接操作字节码:
scss
CGLIB字节码生成架构:
┌─────────────────────────────────────┐
│ Enhancer │
│ - setSuperclass() │
│ - setCallback() │
│ - create() ──────┐ │
└───────────────────┼─────────────────┘
│
▼
┌─────────────────────────────────────┐
│ AbstractClassGenerator │
│ - generate() │
│ - 缓存策略(key → Class) │
└─────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ DefaultGeneratorStrategy │
│ - generate() │
│ - 调用 ASM ClassWriter │
└─────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ASM ClassVisitor │
│ - visit() → 类声明 │
│ - visitMethod() → 方法生成 │
│ - visitField() → 字段生成 │
│ - visitEnd() → 完成写入 │
└─────────────────────────────────────┘
生成两个类:
1. OrderService$$EnhancerByCGLIB:代理类(继承目标类)
2. OrderService$$FastClassByCGLIB:FastClass索引类
CGLIB生成的代理类结构:
swift
public class OrderService$$EnhancerByCGLIB extends OrderService
implements Factory {
// 回调对象(MethodInterceptor)
private MethodInterceptor CGLIB$CALLBACK_0;
// 每个被代理方法对应一个MethodProxy和索引
private static final MethodProxy CGLIB$createOrder$0$Proxy;
private static final int CGLIB$createOrder$0$Index;
// 原始方法的Method对象
private static final Method CGLIB$createOrder$0$Method;
static {
CGLIB$createOrder$0$Method =
ReflectUtils.findMethod("OrderService", "createOrder", "Order");
CGLIB$createOrder$0$Proxy =
MethodProxy.create(
cls1, // OrderService.class
cls2, // OrderService$$EnhancerByCGLIB.class
"(Order)V", // 方法签名
"createOrder", // 父类方法名
"CGLIB$createOrder$0" // 代理类方法名
);
CGLIB$createOrder$0$Index = 12; // FastClass索引
}
// 被代理的方法
public final void createOrder(Order order) {
MethodInterceptor tmp = CGLIB$CALLBACK_0;
if (tmp == null) {
CGLIB$BIND_CALLBACKS(this);
tmp = CGLIB$CALLBACK_0;
}
if (tmp != null) {
// 调用拦截器
tmp.intercept(
this, // obj
CGLIB$createOrder$0$Method, // method
new Object[]{order}, // args
CGLIB$createOrder$0$Proxy // MethodProxy
);
} else {
super.createOrder(order);
}
}
// 原始方法代理(用于invokeSuper)
final void CGLIB$createOrder$0(Order order) {
super.createOrder(order);
}
}
CGLIB生成的FastClass结构:
typescript
public class OrderService$$FastClassByCGLIB extends FastClass {
// 构造器:接收目标类Class对象
public OrderService$$FastClassByCGLIB(Class clazz) {
super(clazz);
}
// 根据方法名和参数类型获取索引
public int getIndex(String name, Class[] params) {
switch(name.hashCode()) {
case -1182772644: // "createOrder".hashCode()
if (params.length == 1 && params[0] == Order.class) {
return 12; // createOrder对应索引12
}
break;
// ... 其他方法
}
return -1;
}
// 根据索引直接调用方法,无需反射
public Object invoke(int index, Object target, Object[] args) {
OrderService obj = (OrderService) target;
switch (index) {
case 12:
obj.createOrder((Order) args[0]);
return null;
case 13:
obj.queryOrder((String) args[0]);
return null;
// ...
default:
throw new IllegalArgumentException("Cannot find matching method");
}
}
// 根据方法签名获取索引(用于MethodProxy)
public int getIndex(Class[] params) {
// 构造器索引
}
// 根据索引创建实例
public Object newInstance(int index, Object[] args) {
switch(index) {
case 0: return new OrderService();
// ...
}
}
}
FastClass机制的核心价值:
scss
方法调用方式对比:
方式1:反射调用(JDK动态代理)
Method.invoke(target, args)
├── 检查方法可见性
├── 参数类型转换
├── 调用Native方法(JNI)
└── 无法被JVM内联优化
方式2:FastClass索引调用(CGLIB)
FastClass.invoke(index, target, args)
├── switch(index) 直接跳转
├── 强转参数类型
└── 直接调用目标方法
性能差异:
- 反射调用:~15-20x 直接调用
- FastClass:~1.2-2x 直接调用(接近原生)
4. 内存模型与元空间占用
swift
动态代理的内存模型:
┌─────────────────────────────────────────┐
│ 元空间(Metaspace) │
│ ┌─────────────────────────────────┐ │
│ │ JDK代理类:com.sun.proxy.$Proxy0 │ │
│ │ - 类结构信息 │ │
│ │ - 静态字段(Method对象) │ │
│ │ - 方法字节码 │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ CGLIB代理类:*$$EnhancerByCGLIB │ │
│ │ - 类结构信息 │ │
│ │ - 静态字段(MethodProxy) │ │
│ │ - 方法字节码 │ │
│ └─────────────────────────────────┘ │
│ ┌─────────────────────────────────┐ │
│ │ CGLIB FastClass:*$$FastClassByCGLIB│ │
│ │ - getIndex() 方法 │ │
│ │ - invoke() 方法(switch表) │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
内存占用估算(单个代理类):
- JDK代理:~2-5KB(取决于接口方法数量)
- CGLIB代理:~5-15KB(代理类 + FastClass)
- 大量代理类时需注意元空间OOM(-XX:MaxMetaspaceSize)
源码深度分析:JDK动态代理核心源码逐行解读
1. Proxy.newProxyInstance() 完整源码
php
// java.lang.reflect.Proxy
/**
* 创建代理实例的核心方法
*
* @param loader 定义代理类的类加载器
* @param interfaces 代理类要实现的接口列表
* @param h 调用处理器(InvocationHandler)
* @return 代理对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
// 【第1步】参数校验:InvocationHandler不能为null
Objects.requireNonNull(h);
// 【第2步】克隆接口数组,防止外部修改影响缓存key
// 这是防御性编程,确保后续使用的接口数组不可变
final Class<?>[] intfs = interfaces.clone();
// 【第3步】SecurityManager安全检查
// 检查当前调用者是否有权限创建代理类
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 【第4步】生成或获取代理类(核心中的核心)
// 此处有缓存机制:如果该接口组合已生成过代理类,直接返回缓存
Class<?> cl = getProxyClass0(loader, intfs);
// 【第5步】通过反射创建代理实例
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取构造器:public $Proxy0(InvocationHandler h)
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
// 如果构造器不可访问(非public),尝试取消访问检查
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 创建实例:new $Proxy0(h)
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
2. getProxyClass0() 与缓存机制
ini
// Proxy.java
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 限制接口数量:最多65535个(JVM规范限制)
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 【关键】从缓存获取或生成代理类
// proxyClassCache是WeakCache<ClassLoader, Class<?>[], Class<?>>
return proxyClassCache.get(loader, interfaces);
}
// WeakCache的get方法(简化版)
public V get(K key, P parameter) {
// key: ClassLoader
// parameter: Class<?>[](接口数组)
Objects.requireNonNull(parameter);
// 清理已被GC的引用
expungeStaleEntries();
// 构建缓存key(ClassLoader的弱引用)
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 获取或创建该ClassLoader对应的ConcurrentMap
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// 构建子key(基于接口数组的WeakReference)
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 获取或创建Supplier(Factory或CacheValue)
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// 获取值(Factory.get()或CacheValue.get())
V value = supplier.get();
if (value != null) {
return value;
}
}
// 首次访问,创建Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
// 替换无效的supplier
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
缓存策略解析:
php
WeakCache结构:
Map<ClassLoader, Map<Key, Class<?>>> proxyClassCache
┌─────────────────────────────────────────────────┐
│ ClassLoader_1 ──► ┌─────────────────────────┐ │
│ │ Key{[I1,I2]} ──► $Proxy0 │ │
│ │ Key{[I1]} ──► $Proxy1 │ │
│ └─────────────────────────┘ │
│ ClassLoader_2 ──► ┌─────────────────────────┐ │
│ │ Key{[I2,I3]} ──► $Proxy2 │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────┘
设计要点:
1. 使用WeakReference包装ClassLoader,避免内存泄漏
2. 接口数组也使用WeakReference
3. 代理类使用WeakReference,当ClassLoader被回收时,
代理类也可被GC回收
3. ProxyClassFactory.apply() 源码
java
// Proxy.java 中的内部类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 代理类名前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 原子计数器,用于生成唯一类名
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// 【1】验证所有接口(非空、是接口、类加载器一致)
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 验证接口是否由指定的类加载器加载
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 验证是否是接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 验证接口唯一性
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 【2】确定代理类的包名
// 规则:如果所有接口都是public,使用com.sun.proxy包
// 如果有非public接口,使用该接口的包名
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; // "com.sun.proxy."
}
// 【3】生成唯一类名
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 【4】生成字节码(核心)
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
// 【5】通过Unsafe.defineClass加载类
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
4. ProxyGenerator.generateProxyClass() 源码
scss
// sun.misc.ProxyGenerator
public static byte[] generateProxyClass(final String name,
Class<?>[] interfaces,
int accessFlags) {
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
// 生成字节码文件
final byte[] classFile = gen.generateClassFile();
// 如果设置了系统属性,保存生成的.class文件到磁盘
// -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
int i = name.lastIndexOf('.');
Path path;
if (i > 0) {
Path dir = Paths.get(name.substring(0, i).replace('.', '/'));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i+1, name.length())
+ ".class");
} else {
path = Paths.get(name + ".class");
}
Files.write(path, classFile);
return null;
} catch (IOException e) {
throw new InternalError(
"I/O exception saving generated file: " + e);
}
}
});
}
return classFile;
}
// 生成类文件的核心方法
private byte[] generateClassFile() {
// 【1】添加方法:hashCode, equals, toString
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
// 【2】添加接口方法
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
// 【3】验证方法签名一致性(返回类型)
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
// 【4】开始生成字节码
try {
// 生成字段:private static Method m0, m1, m2...
methods.add(generateConstructor());
// 生成静态代码块:初始化Method对象
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
methods.add(pm.generateMethod());
}
}
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
// 【5】确保常量池大小在范围内
if (cp.getSize() > 65535) {
throw new IllegalArgumentException("constant pool size limit exceeded");
}
// 【6】写入类文件结构
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
// 魔数
dout.writeInt(0xCAFEBABE);
// 次版本号、主版本号
dout.writeShort(CLASSFILE_MINOR_VERSION);
dout.writeShort(CLASSFILE_MAJOR_VERSION);
// 常量池
cp.write(dout);
// 访问标志
dout.writeShort(accessFlags);
// 类名
dout.writeShort(cp.getClass(dotToSlash(className)));
// 父类名(java.lang.reflect.Proxy)
dout.writeShort(cp.getClass(superclassName));
// 接口数量
dout.writeShort(interfaces.length);
// 接口列表
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
// 字段数量 + 字段列表
dout.writeShort(fields.size());
for (FieldInfo f : fields) {
f.write(dout);
}
// 方法数量 + 方法列表
dout.writeShort(methods.size());
for (MethodInfo m : methods) {
m.write(dout);
}
// 类属性(无)
dout.writeShort(0);
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray();
}
5. 生成的代理类方法示例
typescript
// ProxyMethod.generateMethod() 生成的伪代码
public final void saveUser(String paramString) {
try {
// 调用InvocationHandler.invoke()
// this 是代理对象本身
// m3 是静态字段中保存的Method对象
// new Object[]{paramString} 是参数数组
this.h.invoke(this, m3, new Object[] { paramString });
return;
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
// 静态初始化代码块生成的伪代码
static {
try {
// 获取Method对象并缓存
m1 = Class.forName("java.lang.Object")
.getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("UserService")
.getMethod("saveUser", new Class[] { Class.forName("java.lang.String") });
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
源码深度分析:CGLIB动态代理核心源码逐行解读
1. Enhancer.create() 源码
typescript
// net.sf.cglib.proxy.Enhancer
/**
* 生成代理类的入口方法
*/
public Object create() {
// 表示要创建实例(非仅生成类)
classOnly = false;
// 使用无参构造器
argumentTypes = null;
return createHelper();
}
private Object createHelper() {
// 【1】预验证:检查final类、java.lang.Class等特殊限制
preValidate();
// 【2】生成唯一key(基于父类、接口、回调类型组合)
// KEY_FACTORY是内部接口,用于生成缓存key
Object key = KEY_FACTORY.newInstance(
(superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID
);
// 【3】设置当前key并调用父类的create方法
this.currentKey = key;
Object result = super.create(key);
return result;
}
2. AbstractClassGenerator.create() 源码
ini
// net.sf.cglib.core.AbstractClassGenerator
protected Object create(Object key) {
try {
// 获取类加载器数据(包含缓存)
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache
= new WeakHashMap<>(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
// 设置当前key
this.key = key;
// 【核心】从缓存获取或生成类
Object obj = data.get(this, getUseCache());
// 如果是Class对象,创建实例
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
// 如果是实例,返回下一个实例(用于缓存实例)
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
3. ClassLoaderData.get() 源码
kotlin
// AbstractClassGenerator.ClassLoaderData
public Object get(AbstractClassGenerator gen, boolean useCache) {
if (!useCache) {
// 不使用缓存,直接生成
return gen.generate(ClassLoaderData.this);
} else {
// 使用缓存
Object cachedValue = generatedClasses.get(gen);
return gen.unwrapCachedValue(cachedValue);
}
}
// generatedClasses是LoadingCache,基于FutureTask的并发加载
4. AbstractClassGenerator.generate() 源码
java
// 生成代理类的核心方法
protected Class generate(ClassLoaderData data) {
Class gen;
// 保存当前生成器状态
Object save = CURRENT.get();
CURRENT.set(this);
try {
// 获取类加载器
ClassLoader classLoader = data.getClassLoader();
if (classLoader == null) {
throw new IllegalStateException("ClassLoader is null");
}
synchronized (classLoader) {
// 生成类名:包名.类名$$EnhancerByCGLIB$$hashCode
String name = generateClassName(data.getUniqueNamePredicate());
// 设置类名
data.reserveName(name);
this.setClassName(name);
}
// 使用策略生成字节码
if (attemptLoad) {
try {
// 尝试直接加载(如果已存在)
gen = classLoader.loadClass(getClassName());
} catch (ClassNotFoundException e) {
// 不存在,继续生成
}
}
// 【核心】调用策略生成字节码
byte[] b = strategy.generate(this);
// 获取类名
String className = ClassNameReader.getClassName(new ClassReader(b));
// 转换为ProtectionDomain(如果需要)
ProtectionDomain protectionDomain = getProtectionDomain();
// 【核心】定义类到JVM
synchronized (classLoader) {
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(
className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(
className, b, classLoader, protectionDomain);
}
}
return gen;
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
} finally {
CURRENT.set(save);
}
}
5. DefaultGeneratorStrategy.generate() 源码
scss
// net.sf.cglib.core.DefaultGeneratorStrategy
public byte[] generate(ClassGenerator cg) throws Exception {
// 创建ASM ClassWriter
// COMPUTE_FRAMES:自动计算栈帧(Java 7+需要)
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// 创建转换链
TransformingClassGenerator tfg = new TransformingClassGenerator(
cg,
new ClassTransformerChain(new ClassTransformer[]{
new FieldFilterTransformer(fieldFilter),
new UndeclaredThrowableTransformer(
undeclaredThrowable), // 处理未声明异常
new MethodInterceptorTransformer(), // 处理方法拦截
new NoOpClassTransformer() // 无操作转换器(占位)
})
);
// 生成字节码
tfg.generateClass(cw);
// 返回字节码数组
return cw.toByteArray();
}
6. MethodProxy.invokeSuper() 源码(FastClass调用)
scss
// net.sf.cglib.proxy.MethodProxy
/**
* 调用父类(目标类)的方法
* 这是CGLIB性能优化的核心:使用FastClass避免反射
*/
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
// 初始化FastClassInfo(懒加载)
init();
FastClassInfo fci = fastClassInfo;
// 直接通过FastClass索引调用
// fci.f2: 目标类的FastClass
// fci.i2: 方法在FastClass中的索引
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
// 包装并抛出目标异常
throw e.getTargetException();
}
}
// init() 方法:懒加载FastClass
private void init() {
if (fastClassInfo == null) {
// 获取或创建FastClassInfo
FastClassInfo temp;
synchronized (initLock) {
if (fastClassInfo == null) {
// 创建FastClassInfo
temp = new FastClassInfo();
// 为目标类创建FastClass
temp.f1 = helper(ci1, fastClassHooks.getFastClass(ci1));
// 为代理类创建FastClass
temp.f2 = helper(ci2, fastClassHooks.getFastClass(ci2));
// 获取方法索引
temp.i1 = temp.f1.getIndex(sig1); // 代理类方法索引
temp.i2 = temp.f2.getIndex(sig2); // 目标类方法索引
fastClassInfo = temp;
}
}
}
}
// FastClassInfo内部类
private static class FastClassInfo {
FastClass f1; // 代理类的FastClass
FastClass f2; // 目标类的FastClass
int i1; // 代理类方法索引
int i2; // 目标类方法索引
}
7. FastClass.invoke() 源码
csharp
// net.sf.cglib.reflect.FastClass
/**
* FastClass的核心:通过索引直接调用方法
*/
public Object invoke(int index, Object target, Object[] args)
throws InvocationTargetException {
// 子类(生成的FastClass)会重写此方法
// 典型实现如下:
// 伪代码(由ASM生成):
// switch (index) {
// case 12:
// ((OrderService)target).createOrder((Order)args[0]);
// return null;
// case 13:
// return ((OrderService)target).queryOrder((String)args[0]);
// // ...
// }
return invokeMethod(index, target, args);
}
// 生成的FastClass示例方法(伪代码):
public int getIndex(String name, Class[] params) {
switch(name.hashCode()) {
case -1182772644: // "createOrder"
if (params.length == 1 && params[0] == Order.class) {
return 12;
}
break;
case -838846263: // "queryOrder"
if (params.length == 1 && params[0] == String.class) {
return 13;
}
break;
}
return -1;
}
实战案例:完整可运行的JDK动态代理
1. 基础JDK动态代理
typescript
import java.lang.reflect.*;
/**
* 目标接口
*/
public interface OrderService {
void createOrder(String orderId);
String queryOrder(String orderId);
boolean cancelOrder(String orderId);
}
/**
* 目标实现
*/
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String orderId) {
System.out.println("[业务] 创建订单: " + orderId);
}
@Override
public String queryOrder(String orderId) {
System.out.println("[业务] 查询订单: " + orderId);
return "Order{id=" + orderId + ", status=PAID}";
}
@Override
public boolean cancelOrder(String orderId) {
System.out.println("[业务] 取消订单: " + orderId);
return true;
}
}
/**
* 日志拦截器(InvocationHandler)
*/
public class LogInvocationHandler implements InvocationHandler {
private final Object target;
public LogInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[JDK代理] ┌───────────────────────────────");
System.out.println("[JDK代理] │ 方法: " + method.getDeclaringClass().getName()
+ "." + method.getName());
System.out.println("[JDK代理] │ 参数: " + Arrays.toString(args));
long start = System.currentTimeMillis();
Object result;
try {
// 调用目标对象的真实方法
result = method.invoke(target, args);
long cost = System.currentTimeMillis() - start;
System.out.println("[JDK代理] │ 结果: " + result);
System.out.println("[JDK代理] │ 耗时: " + cost + "ms ✓");
System.out.println("[JDK代理] └───────────────────────────────");
return result;
} catch (InvocationTargetException e) {
long cost = System.currentTimeMillis() - start;
System.out.println("[JDK代理] │ 异常: " + e.getTargetException().getMessage());
System.out.println("[JDK代理] │ 耗时: " + cost + "ms ✗");
System.out.println("[JDK代理] └───────────────────────────────");
throw e.getTargetException();
}
}
/**
* 创建代理对象的工厂方法
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Object target, Class<T> iface) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{iface},
new LogInvocationHandler(target)
);
}
}
/**
* 测试类
*/
public class JdkProxyTest {
public static void main(String[] args) {
// 创建目标对象
OrderService target = new OrderServiceImpl();
// 创建代理对象
OrderService proxy = LogInvocationHandler.createProxy(
target, OrderService.class);
System.out.println("=== JDK动态代理测试 ===\n");
// 调用代理方法
proxy.createOrder("ORD-2024-001");
System.out.println();
String result = proxy.queryOrder("ORD-2024-001");
System.out.println("返回值: " + result);
System.out.println();
boolean cancelled = proxy.cancelOrder("ORD-2024-001");
System.out.println("取消结果: " + cancelled);
// 验证代理类信息
System.out.println("\n=== 代理类信息 ===");
System.out.println("类名: " + proxy.getClass().getName());
System.out.println("父类: " + proxy.getClass().getSuperclass().getName());
System.out.println("实现接口: ");
for (Class<?> intf : proxy.getClass().getInterfaces()) {
System.out.println(" - " + intf.getName());
}
}
}
运行结果:
ini
=== JDK动态代理测试 ===
[JDK代理] ┌───────────────────────────────
[JDK代理] │ 方法: OrderService.createOrder
[JDK代理] │ 参数: [ORD-2024-001]
[业务] 创建订单: ORD-2024-001
[JDK代理] │ 结果: null
[JDK代理] │ 耗时: 1ms ✓
[JDK代理] └───────────────────────────────
[JDK代理] ┌───────────────────────────────
[JDK代理] │ 方法: OrderService.queryOrder
[JDK代理] │ 参数: [ORD-2024-001]
[业务] 查询订单: ORD-2024-001
[JDK代理] │ 结果: Order{id=ORD-2024-001, status=PAID}
[JDK代理] │ 耗时: 0ms ✓
[JDK代理] └───────────────────────────────
返回值: Order{id=ORD-2024-001, status=PAID}
=== 代理类信息 ===
类名: com.sun.proxy.$Proxy0
父类: java.lang.reflect.Proxy
实现接口:
- OrderService
2. 查看JDK动态代理生成的类文件
arduino
public class ProxyClassDumper {
public static void main(String[] args) {
// 设置系统属性:保存生成的代理类文件
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
OrderService target = new OrderServiceImpl();
OrderService proxy = LogInvocationHandler.createProxy(
target, OrderService.class);
proxy.createOrder("TEST-001");
// 生成的.class文件将保存在当前目录的 com/sun/proxy/ 下
// 使用 javap -c com.sun.proxy.$Proxy0 可以查看反汇编代码
}
}
实战案例:完整可运行的CGLIB动态代理
1. 基础CGLIB动态代理
typescript
import net.sf.cglib.proxy.*;
/**
* 没有接口的目标类
*/
public class UserService {
public void saveUser(String name) {
System.out.println("[业务] 保存用户: " + name);
}
public String getUser(Long id) {
System.out.println("[业务] 查询用户: " + id);
return "User{id=" + id + ", name=张三}";
}
public boolean deleteUser(Long id) {
System.out.println("[业务] 删除用户: " + id);
return true;
}
// final方法不会被代理
public final void finalMethod() {
System.out.println("[业务] final方法");
}
}
/**
* CGLIB拦截器(MethodInterceptor)
*/
public class LogMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("[CGLIB代理] ┌───────────────────────────────");
System.out.println("[CGLIB代理] │ 方法: " + method.getDeclaringClass().getName()
+ "." + method.getName());
System.out.println("[CGLIB代理] │ 参数: " + Arrays.toString(args));
long start = System.currentTimeMillis();
Object result;
try {
// 使用invokeSuper调用父类方法,比反射快
// 注意:这里必须使用invokeSuper,而不是invoke
result = proxy.invokeSuper(obj, args);
long cost = System.currentTimeMillis() - start;
System.out.println("[CGLIB代理] │ 结果: " + result);
System.out.println("[CGLIB代理] │ 耗时: " + cost + "ms ✓");
System.out.println("[CGLIB代理] └───────────────────────────────");
return result;
} catch (Throwable t) {
long cost = System.currentTimeMillis() - start;
System.out.println("[CGLIB代理] │ 异常: " + t.getMessage());
System.out.println("[CGLIB代理] │ 耗时: " + cost + "ms ✗");
System.out.println("[CGLIB代理] └───────────────────────────────");
throw t;
}
}
/**
* 创建代理对象的工厂方法
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> clazz) {
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(clazz);
// 设置回调
enhancer.setCallback(new LogMethodInterceptor());
return (T) enhancer.create();
}
}
/**
* 测试类
*/
public class CglibProxyTest {
public static void main(String[] args) {
// 创建代理对象
UserService proxy = LogMethodInterceptor.createProxy(UserService.class);
System.out.println("=== CGLIB动态代理测试 ===\n");
proxy.saveUser("李四");
System.out.println();
String result = proxy.getUser(1001L);
System.out.println("返回值: " + result);
System.out.println();
boolean deleted = proxy.deleteUser(1001L);
System.out.println("删除结果: " + deleted);
System.out.println();
// final方法不会被拦截
System.out.println("=== final方法测试 ===");
proxy.finalMethod();
// 验证代理类信息
System.out.println("\n=== 代理类信息 ===");
System.out.println("类名: " + proxy.getClass().getName());
System.out.println("父类: " + proxy.getClass().getSuperclass().getName());
}
}
运行结果:
swift
=== CGLIB动态代理测试 ===
[CGLIB代理] ┌───────────────────────────────
[CGLIB代理] │ 方法: UserService.saveUser
[CGLIB代理] │ 参数: [李四]
[业务] 保存用户: 李四
[CGLIB代理] │ 结果: null
[CGLIB代理] │ 耗时: 1ms ✓
[CGLIB代理] └───────────────────────────────
=== final方法测试 ===
[业务] final方法
=== 代理类信息 ===
类名: UserService$$EnhancerByCGLIB$$12345678
父类: UserService
2. CGLIB多种Callback组合
csharp
import net.sf.cglib.proxy.*;
/**
* 固定值返回拦截器
*/
public class FixedValueInterceptor implements FixedValue {
@Override
public Object loadObject() throws Exception {
return "固定返回值";
}
}
/**
* 懒加载拦截器
*/
public class LazyLoaderInterceptor implements LazyLoader {
@Override
public Object loadObject() throws Exception {
System.out.println("[懒加载] 初始化重对象...");
return new HeavyObject();
}
}
/**
* 多Callback配置示例
*/
public class MultiCallbackTest {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
// 设置多个回调
Callback[] callbacks = new Callback[]{
new LogMethodInterceptor(), // 索引0:日志拦截
new FixedValueInterceptor(), // 索引1:固定值返回
NoOp.INSTANCE // 索引2:无操作
};
enhancer.setCallbacks(callbacks);
// 设置回调过滤器:根据方法选择使用哪个回调
enhancer.setCallbackFilter(new CallbackFilter() {
@Override
public int accept(Method method) {
if (method.getName().equals("getUser")) {
return 1; // 使用FixedValueInterceptor
} else if (method.getName().equals("finalMethod")) {
return 2; // 使用NoOp(不拦截)
}
return 0; // 默认使用LogMethodInterceptor
}
});
UserService proxy = (UserService) enhancer.create();
System.out.println("=== 多Callback测试 ===");
proxy.saveUser("王五"); // 使用日志拦截
System.out.println();
String result = proxy.getUser(1L); // 使用固定值返回
System.out.println("返回值: " + result);
}
}
实战案例:基于动态代理的迷你AOP框架
1. 核心注解与接口
kotlin
import java.lang.annotation.*;
/**
* 环绕通知注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Around {
Class<? extends Interceptor>[] value();
}
/**
* 拦截器接口
*/
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
}
/**
* 调用链上下文
*/
public class Invocation {
private final Object target;
private final Method method;
private final Object[] args;
private final Interceptor[] interceptors;
private int index;
public Invocation(Object target, Method method, Object[] args,
Interceptor[] interceptors) {
this.target = target;
this.method = method;
this.args = args;
this.interceptors = interceptors;
this.index = 0;
}
/**
* 推进调用链
*/
public Object proceed() throws Throwable {
if (index < interceptors.length) {
return interceptors[index++].intercept(this);
}
return method.invoke(target, args);
}
public Method getMethod() { return method; }
public Object[] getArgs() { return args; }
public Object getTarget() { return target; }
}
2. 拦截器实现
java
/**
* 日志拦截器
*/
public class LogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
String name = invocation.getMethod().getName();
System.out.println("[AOP-Log] → 进入方法: " + name);
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long cost = System.currentTimeMillis() - start;
System.out.println("[AOP-Log] ← 退出方法: " + name + ", 耗时: " + cost + "ms");
return result;
}
}
/**
* 事务拦截器
*/
public class TransactionInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
String name = invocation.getMethod().getName();
System.out.println("[AOP-TX] 开启事务: " + name);
try {
Object result = invocation.proceed();
System.out.println("[AOP-TX] 提交事务: " + name);
return result;
} catch (Exception e) {
System.out.println("[AOP-TX] 回滚事务: " + name + ", 原因: " + e.getMessage());
throw e;
}
}
}
/**
* 权限拦截器
*/
public class AuthInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("[AOP-Auth] 校验权限: " + invocation.getMethod().getName());
// 模拟权限校验
System.out.println("[AOP-Auth] 权限校验通过 ✓");
return invocation.proceed();
}
}
3. 代理工厂
scss
/**
* AOP代理工厂
*/
public class AopProxyFactory {
/**
* 为目标对象创建AOP代理
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(T target) {
Class<?> clazz = target.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
if (interfaces.length == 0) {
// 无接口,使用CGLIB
return createCglibProxy(target);
}
// 有接口,使用JDK动态代理
return (T) Proxy.newProxyInstance(
clazz.getClassLoader(),
interfaces,
(proxy, method, args) -> {
Around around = method.getAnnotation(Around.class);
if (around == null) {
// 无注解,直接调用
return method.invoke(target, args);
}
// 创建拦截器链
Interceptor[] interceptors = new Interceptor[around.value().length];
for (int i = 0; i < around.value().length; i++) {
interceptors[i] = around.value()[i]
.getDeclaredConstructor().newInstance();
}
// 执行拦截器链
Invocation invocation = new Invocation(
target, method, args, interceptors);
return invocation.proceed();
}
);
}
/**
* CGLIB代理创建
*/
@SuppressWarnings("unchecked")
private static <T> T createCglibProxy(T target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
Around around = method.getAnnotation(Around.class);
if (around == null) {
return proxy.invokeSuper(obj, args);
}
Interceptor[] interceptors = new Interceptor[around.value().length];
for (int i = 0; i < around.value().length; i++) {
interceptors[i] = around.value()[i]
.getDeclaredConstructor().newInstance();
}
Invocation invocation = new Invocation(
target, method, args, interceptors);
return invocation.proceed();
});
return (T) enhancer.create();
}
}
4. 业务接口与实现
arduino
/**
* 支付服务接口
*/
public interface PayService {
@Around({LogInterceptor.class, AuthInterceptor.class, TransactionInterceptor.class})
void pay(String orderId, double amount);
@Around({LogInterceptor.class})
String queryPayStatus(String orderId);
// 无注解,不拦截
String getServiceName();
}
/**
* 支付服务实现
*/
public class PayServiceImpl implements PayService {
@Override
public void pay(String orderId, double amount) {
System.out.println("[业务] 支付订单: " + orderId + ", 金额: ¥" + amount);
}
@Override
public String queryPayStatus(String orderId) {
System.out.println("[业务] 查询支付状态: " + orderId);
return "PAID";
}
@Override
public String getServiceName() {
return "PayService_v1.0";
}
}
5. 测试类
csharp
/**
* 迷你AOP框架测试
*/
public class MiniAopTest {
public static void main(String[] args) {
System.out.println("=== 迷你AOP框架测试 ===\n");
// 创建目标对象和代理对象
PayService target = new PayServiceImpl();
PayService proxy = AopProxyFactory.createProxy(target);
// 测试1:多拦截器链
System.out.println("--- 测试1:支付(日志+权限+事务) ---");
proxy.pay("2024001", 199.99);
System.out.println();
// 测试2:单拦截器
System.out.println("--- 测试2:查询状态(仅日志) ---");
String status = proxy.queryPayStatus("2024001");
System.out.println("查询结果: " + status);
System.out.println();
// 测试3:无拦截器
System.out.println("--- 测试3:获取服务名(无拦截) ---");
String name = proxy.getServiceName();
System.out.println("服务名: " + name);
}
}
运行结果:
ini
=== 迷你AOP框架测试 ===
--- 测试1:支付(日志+权限+事务) ---
[AOP-Log] → 进入方法: pay
[AOP-Auth] 校验权限: pay
[AOP-Auth] 权限校验通过 ✓
[AOP-TX] 开启事务: pay
[业务] 支付订单: 2024001, 金额: ¥199.99
[AOP-TX] 提交事务: pay
[AOP-Log] ← 退出方法: pay, 耗时: 2ms
--- 测试2:查询状态(仅日志) ---
[AOP-Log] → 进入方法: queryPayStatus
[业务] 查询支付状态: 2024001
[AOP-Log] ← 退出方法: queryPayStatus, 耗时: 1ms
查询结果: PAID
--- 测试3:获取服务名(无拦截) ---
服务名: PayService_v1.0
对比分析:JDK动态代理 vs CGLIB vs AspectJ vs Javassist
1. 四种代理技术全方位对比
swift
代理技术对比矩阵:
┌────────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
│ 特性 │ JDK动态代理 │ CGLIB │ AspectJ │ Javassist │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 代理方式 │ 实现接口 │ 继承类 │ 字节码织入 │ 字节码生成 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 依赖 │ JDK内置 │ 第三方库 │ 编译器插件 │ 第三方库 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 目标要求 │ 必须实现接口 │ 非final类 │ 任何类/方法 │ 任何类 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 方法限制 │ 无 │ 不能代理final │ 无限制 │ 无 │
│ │ │ 和static方法 │ │ │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 调用机制 │ 反射调用 │ FastClass │ 直接调用 │ 直接调用 │
│ │ Method.invoke│ 索引调用 │(字节码替换)│(生成类) │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 性能 │ 较慢(反射) │ 较快 │ 最快(原生) │ 较快 │
│ 相对直接调用 │ ~15-20x │ ~1.2-2x │ ~1x(无损耗)│ ~2-3x │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 生成速度 │ 快 │ 较慢 │ 编译时完成 │ 中等 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 内存占用 │ 小 │ 较大 │ 无额外内存 │ 中等 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 侵入性 │ 低 │ 低 │ 高(需工具) │ 低 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 调试难度 │ 低 │ 中等 │ 高 │ 中等 │
├────────────────┼─────────────┼─────────────┼─────────────┼─────────────┤
│ 适用场景 │ 有接口的类 │ 无接口的类 │ 极致性能AOP │ 运行时字节码 │
│ │ Spring默认 │ SpringBoot默认│ 金融交易系统 │ 操作 │
└────────────────┴─────────────┴─────────────┴─────────────┴─────────────┘
2. 详细特性对比
| 特性 | JDK动态代理 | CGLIB | AspectJ | Javassist |
|---|---|---|---|---|
| 代理方式 | 实现接口 | 继承类 | 字节码织入 | 字节码生成 |
| 依赖 | JDK内置 | cglib:cglib:3.x |
AspectJ编译器/加载器 | org.javassist:javassist |
| 目标要求 | 必须实现接口 | 非final类,非static方法 | 任何类/方法 | 任何类 |
| 方法限制 | 仅代理接口方法 | 不能代理final/static方法 | 无限制 | 无限制 |
| 调用机制 | 反射调用 | FastClass索引调用 | 直接字节码调用 | 直接调用 |
| 性能 | 较慢(15-20x) | 较快(1.2-2x) | 最快(1x) | 较快(2-3x) |
| 生成速度 | 快 | 较慢 | 编译时 | 中等 |
| 内存占用 | 小(单类) | 较大(代理+FastClass) | 无额外内存 | 中等 |
| 侵入性 | 低 | 低 | 高 | 低 |
| 调试难度 | 低(可dump类文件) | 中等 | 高 | 中等 |
| 学习曲线 | 低 | 中等 | 高 | 中等 |
| 典型应用 | Spring AOP(默认) | Spring Boot AOP(默认) | 金融交易系统 | Hibernate |
3. 静态代理 vs 动态代理
静态代理 vs 动态代理:
┌─────────────────┬──────────────────┬──────────────────┐
│ 特性 │ 静态代理 │ 动态代理 │
├─────────────────┼──────────────────┼──────────────────┤
│ 代码生成时机 │ 编译前手写 │ 运行时自动生成 │
├─────────────────┼──────────────────┼──────────────────┤
│ 代码冗余 │ 高(每个目标类 │ 低(通用工厂适配 │
│ │ 都需代理类) │ 所有接口/类) │
├─────────────────┼──────────────────┼──────────────────┤
│ 维护成本 │ 高(接口变更需 │ 低(自动生成, │
│ │ 同步修改代理类) │ 无需手动维护) │
├─────────────────┼──────────────────┼──────────────────┤
│ 灵活性 │ 低(代理逻辑固定)│ 高(运行时决定 │
│ │ │ 代理行为) │
├─────────────────┼──────────────────┼──────────────────┤
│ 性能 │ 直接调用(无损耗)│ 有代理开销 │
├─────────────────┼──────────────────┼──────────────────┤
│ 适用场景 │ 代理逻辑固定、 │ 通用横切逻辑 │
│ │ 目标类数量少 │(日志、事务、权限)│
└─────────────────┴──────────────────┴──────────────────┘
4. 性能差异分析
objectivec
方法调用性能对比(相对倍数,直接调用=1x):
直接调用: ████ 1x(基准)
AspectJ织入: ████ 1x(无额外开销)
CGLIB invokeSuper: ████ 1.2x(FastClass switch跳转)
Javassist代理: ████████ 2.5x(直接调用,少量开销)
CGLIB intercept: ████████████████████ 20x(反射+额外逻辑)
JDK代理: ████████████████████████████████ 15-20x(反射调用)
反射直接调用: ████████████████████████████████ 15-20x
说明:
- CGLIB使用invokeSuper时性能接近原生
- CGLIB使用intercept+反射时性能与JDK代理相当
- JDK代理的性能损耗主要在Method.invoke()的反射开销
性能分析:Benchmark数据与复杂度分析
1. JMH基准测试代码
java
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.lang.reflect.*;
import java.util.concurrent.TimeUnit;
/**
* JMH性能基准测试
*
* 运行方式:
* mvn dependency:copy -Dartifact=org.openjdk.jmh:jmh-core:1.37
* javac -cp jmh-core-1.37.jar:jmh-generator-annprocess-1.37.jar *.java
* java -cp .:jmh-core-1.37.jar:jmh-generator-annprocess-1.37.jar ProxyBenchmark
*/
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(1)
public class ProxyBenchmark {
private OrderService target;
private OrderService jdkProxy;
private OrderService cglibProxy;
private Method targetMethod;
private Method proxyMethod;
@Setup
public void setup() throws Exception {
// 目标对象
target = new OrderServiceImpl();
// JDK动态代理
jdkProxy = (OrderService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{OrderService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(target, args);
}
}
);
// CGLIB代理(使用NoOp避免额外逻辑)
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setSuperclass(OrderServiceImpl.class);
enhancer.setCallback(new net.sf.cglib.proxy.MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
net.sf.cglib.proxy.MethodProxy proxy)
throws Throwable {
return proxy.invokeSuper(obj, args);
}
});
cglibProxy = (OrderService) enhancer.create();
// 预取Method对象
targetMethod = OrderServiceImpl.class.getMethod("createOrder", String.class);
proxyMethod = OrderService.class.getMethod("createOrder", String.class);
}
@Benchmark
public void directCall() {
target.createOrder("TEST-001");
}
@Benchmark
public void jdkProxyCall() {
jdkProxy.createOrder("TEST-001");
}
@Benchmark
public void cglibProxyCall() {
cglibProxy.createOrder("TEST-001");
}
@Benchmark
public void reflectionCall() throws Exception {
targetMethod.invoke(target, "TEST-001");
}
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(ProxyBenchmark.class.getSimpleName())
.build();
new Runner(opt).run();
}
}
2. 基准测试结果分析
bash
JMH基准测试结果(典型值,单位:纳秒/调用):
Benchmark Mode Cnt Score Error Units
------------------------------------------------------------------
ProxyBenchmark.directCall avgt 5 5.2 ± 0.3 ns/op
ProxyBenchmark.cglibProxyCall avgt 5 7.1 ± 0.5 ns/op
ProxyBenchmark.reflectionCall avgt 5 85.3 ± 4.2 ns/op
ProxyBenchmark.jdkProxyCall avgt 5 92.6 ± 5.1 ns/op
性能分析:
┌─────────────────┬──────────┬────────────────────────────────────┐
│ 调用方式 │ 相对性能 │ 原因分析 │
├─────────────────┼──────────┼────────────────────────────────────┤
│ 直接调用 │ 1x │ 直接字节码调用,可被JIT内联优化 │
├─────────────────┼──────────┼────────────────────────────────────┤
│ CGLIB invokeSuper│ 1.4x │ FastClass switch跳转,几乎无额外开销 │
├─────────────────┼──────────┼────────────────────────────────────┤
│ 反射调用 │ 16.4x │ Method.invoke()需检查可见性、 │
│ │ │ 参数转换、JNI调用,无法内联 │
├─────────────────┼──────────┼────────────────────────────────────┤
│ JDK代理 │ 17.8x │ 反射调用 + 代理层转发开销 │
└─────────────────┴──────────┴────────────────────────────────────┘
3. 复杂度分析
scss
代理类生成的复杂度:
时间复杂度:
- JDK代理:O(n),n为接口方法数
├── 生成类头:O(1)
├── 遍历接口方法:O(n)
├── 生成每个方法的字节码:O(1)
└── 写入类文件:O(n)
- CGLIB:O(n),n为目标类方法数
├── ASM遍历目标类:O(n)
├── 为每个方法生成代理:O(1)
├── 生成FastClass:O(n)
└── 常量和方法数常数更大
空间复杂度:
- JDK代理:O(n)
├── 类结构:O(1)
├── 静态Method字段:O(n)
└── 方法字节码:O(n)
- CGLIB:O(n)
├── 代理类:O(n)
├── FastClass类:O(n)
└── 总体内存占用是JDK的2-3倍
调用时间复杂度:
- 直接调用:O(1)
- JDK代理:O(1),但常数大(反射+JNI)
- CGLIB FastClass:O(1),常数小(switch跳转)
4. 性能优化建议
markdown
动态代理性能优化策略:
1. 代理类缓存
┌─────────────────────────────────────────┐
│ JDK Proxy:内置WeakCache,无需额外处理 │
│ CGLIB:内置缓存,但注意key的生成策略 │
└─────────────────────────────────────────┘
2. 减少反射调用
┌─────────────────────────────────────────┐
│ JDK代理:Method对象已在静态块缓存 │
│ CGLIB:优先使用invokeSuper而非invoke │
│ 通用:缓存Method对象,避免重复getMethod() │
└─────────────────────────────────────────┘
3. 避免代理嵌套
┌─────────────────────────────────────────┐
│ 代理A包装代理B,会导致双重转发开销 │
│ 如需多层代理,考虑责任链模式替代 │
└─────────────────────────────────────────┘
4. 选择合适代理技术
┌─────────────────────────────────────────┐
│ 高频调用(>10000次/秒):考虑AspectJ │
│ 中频调用(1000-10000次/秒):CGLIB │
│ 低频调用(<1000次/秒):JDK代理 │
└─────────────────────────────────────────┘
常见陷阱与最佳实践
陷阱1:InvocationHandler中递归调用proxy导致栈溢出
java
// ❌ 错误示例:StackOverflowError
public class WrongInvocationHandler implements InvocationHandler {
private final Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始调用...");
// 致命错误:调用proxy会再次触发invoke(),导致无限递归
return method.invoke(proxy, args); // StackOverflowError!
}
}
// ✅ 正确示例:调用target真实对象
public class CorrectInvocationHandler implements InvocationHandler {
private final Object target;
public CorrectInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始调用...");
// 正确:调用目标对象,而非代理对象
return method.invoke(target, args);
}
}
陷阱2:同类方法调用导致代理失效(Spring AOP经典问题)
typescript
@Service
public class OrderService {
@Transactional
public void createOrder(Order order) {
// 事务逻辑...
saveOrderItem(order); // ❌ 直接调用,代理不生效
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveOrderItem(Order order) {
// 需要独立事务,但此处不会生效!
}
}
/*
原因分析:
调用方 ──► OrderService代理对象
│
▼
createOrder()
│
├── 事务拦截器生效(开启事务)
├── this.saveOrderItem() ◄── 注意:这里是this!
│ │
│ └── 直接调用目标方法,不走代理
│ 事务拦截器不生效
└── 事务提交
解决方案:
*/
// 方案1:注入自身代理(不推荐,循环依赖风险)
@Service
public class OrderService {
@Autowired
private OrderService self; // 注入代理对象
public void createOrder(Order order) {
self.saveOrderItem(order); // ✅ 通过代理调用
}
}
// 方案2:使用AopContext获取当前代理(推荐)
@Service
public class OrderService {
public void createOrder(Order order) {
// 获取当前代理对象
((OrderService) AopContext.currentProxy())
.saveOrderItem(order); // ✅ 通过代理调用
}
}
// 注意:需配置@EnableAspectJAutoProxy(exposeProxy = true)
// 方案3:拆分到不同类(最佳实践)
@Service
public class OrderService {
@Autowired
private OrderItemService itemService;
public void createOrder(Order order) {
itemService.saveOrderItem(order); // ✅ 不同类,代理生效
}
}
陷阱3:忽略CGLIB对final的限制
csharp
// ❌ 错误:final类无法被CGLIB代理
public final class UserService {
public void save() { }
}
// ❌ 错误:final方法不会被拦截
public class UserService {
public final void save() { } // CGLIB无法重写此方法
}
// ✅ 正确:需要代理的方法不要声明为final
public class UserService {
public void save() { } // CGLIB可以重写并拦截
}
陷阱4:忽略类加载器隔离问题
scss
// ❌ 错误:接口和目标类由不同类加载器加载
ClassLoader interfaceLoader = Interface.class.getClassLoader();
ClassLoader targetLoader = target.getClass().getClassLoader();
// 如果两者不一致,可能导致 ClassCastException
// 或 ClassNotFoundException
// ✅ 正确:使用统一的类加载器
ClassLoader loader = target.getClass().getClassLoader();
// 确保接口也能被该加载器加载
// 在OSGi、Tomcat等多层类加载器环境中尤其要注意
陷阱5:JDK代理的equals/hashCode陷阱
typescript
// JDK代理继承java.lang.Proxy,equals/hashCode行为特殊
// 如果InvocationHandler实现不当,可能导致问题
// ❌ 错误示例:代理对象无法正确放入HashMap
Map<Proxy, String> map = new HashMap<>();
map.put(proxy1, "value1");
// proxy1.equals(proxy2) 会调用InvocationHandler.invoke()
// 如果handler逻辑不当,可能导致不一致
// ✅ 正确做法
public class SafeInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 对Object的方法(equals/hashCode/toString)特殊处理
if (method.getDeclaringClass() == Object.class) {
return method.invoke(target, args);
}
// 其他方法走代理逻辑
return method.invoke(target, args);
}
}
陷阱6:CGLIB代理对象的类型判断
scss
// ❌ 错误:使用getClass() == UserService.class判断
UserService proxy = CglibProxy.createProxy(UserService.class);
if (proxy.getClass() == UserService.class) { // false!
// 永远不会执行
}
// ✅ 正确:使用instanceof判断
if (proxy instanceof UserService) { // true
// 正确
}
// ✅ 正确:Spring中判断是否是代理对象
if (AopUtils.isAopProxy(proxy)) {
// 是代理对象
}
if (AopUtils.isJdkDynamicProxy(proxy)) {
// JDK动态代理
}
if (AopUtils.isCglibProxy(proxy)) {
// CGLIB代理
}
陷阱7:代理对象的序列化问题
java
// JDK代理:实现Serializable接口时需注意
// 代理类默认不实现Serializable,即使目标接口实现了
// ✅ 正确:确保InvocationHandler实现Serializable
public class SerializableHandler implements InvocationHandler, Serializable {
private final Object target;
public SerializableHandler(Object target) {
this.target = target;
}
// ...
}
// CGLIB代理:需要实现Factory接口才能正确序列化
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Target.class);
enhancer.setCallback(callback);
enhancer.setUseFactory(true); // 启用Factory接口
最佳实践总结
swift
动态代理最佳实践清单:
┌─────────────────────────────────────────────────────────────┐
│ 1. 设计层面 │
│ ├── 优先基于接口设计(便于JDK代理,减少依赖) │
│ ├── 避免final类/方法(兼容CGLIB代理) │
│ └── 同类内部调用需考虑代理失效问题 │
├─────────────────────────────────────────────────────────────┤
│ 2. 性能层面 │
│ ├── 高频场景考虑AspectJ编译时织入 │
│ ├── CGLIB优先使用invokeSuper │
│ └── 避免多层代理嵌套 │
├─────────────────────────────────────────────────────────────┤
│ 3. 调试层面 │
│ ├── 设置-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true │
│ ├── 使用javap -c反汇编查看生成的类 │
│ └── Spring中设置@EnableAspectJAutoProxy(exposeProxy=true) │
├─────────────────────────────────────────────────────────────┤
│ 4. 类加载器层面 │
│ ├── 确保代理类加载器能加载目标接口 │
│ ├── OSGi/Tomcat环境注意类加载器隔离 │
│ └── 避免接口和目标类由不同加载器加载 │
├─────────────────────────────────────────────────────────────┤
│ 5. Spring集成层面 │
│ ├── 优先使用接口:自动使用JDK代理 │
│ ├── 无接口时开启proxyTargetClass=true使用CGLIB │
│ ├── 注意@Async、@Transactional的代理顺序 │
│ └── 同类调用使用AopContext.currentProxy() │
└─────────────────────────────────────────────────────────────┘
面试题与参考答案
面试题1:为什么JDK动态代理调用方法比直接调用慢?
参考答案:
JDK动态代理慢主要有三个原因:
- 反射调用开销 :
Method.invoke()需要进行运行时检查(方法可见性、参数类型匹配),并通过JNI调用Native方法 - 代理层转发 :调用经过
$Proxy0→InvocationHandler.invoke()→ 反射调用目标方法,多了两层转发 - 无法内联优化:JVM JIT编译器难以对反射调用进行方法内联优化
JDK 8后对反射做了优化(使用 MethodAccessor 生成字节码),但仍有性能差距。对性能极端敏感的场景,可用 MethodHandle 或 LambdaMetafactory 替代。
scss
调用链路对比:
直接调用:
调用方 ──► 目标方法(直接跳转,可内联)
JDK代理:
调用方 ──► $Proxy0.saveUser()
└── super.h.invoke(this, m3, args)
└── InvocationHandler.invoke()
└── Method.invoke(target, args)
└── JNI Native调用
└── 目标方法
面试题2:CGLIB的FastClass机制是什么?为什么它比反射快?
参考答案:
FastClass是CGLIB生成的辅助类,核心思想是用整数索引替代方法名+参数类型的字符串匹配。
csharp
// FastClass的典型实现(由ASM生成)
public int getIndex(String name, Class[] params) {
// 通过hashCode快速定位
switch(name.hashCode()) {
case -1182772644:
if (params.length == 1 && params[0] == Order.class) {
return 12; // 直接返回索引
}
}
return -1;
}
public Object invoke(int index, Object target, Object[] args) {
switch (index) {
case 12:
((OrderService)target).createOrder((Order)args[0]);
return null;
// ...
}
}
为什么比反射快:
- 反射调用 :
Method.invoke()需要解析方法签名、检查访问权限、JNI调用 - FastClass :
switch(index)直接跳转到方法调用,是本地Java调用 - 性能对比:FastClass接近直接调用(~1.2x),反射调用慢15-20倍
面试题3:Spring中@Transactional失效的几种场景?
参考答案:
Spring AOP基于动态代理实现,@Transactional失效的常见场景:
-
同类内部方法调用(this调用不走代理)
csharppublic void methodA() { this.methodB(); // @Transactional失效 } -
方法不是public :
@Transactional默认只能应用于public方法 -
异常被吞掉或未抛给代理层:
typescript@Transactional public void method() { try { // 业务逻辑 } catch (Exception e) { // 吞掉异常,事务不会回滚 } } -
目标类未交给Spring管理:未被Spring容器管理的Bean,AOP不生效
-
数据库引擎不支持事务:如MySQL的MyISAM引擎
-
异步方法中调用事务方法 :
@Async会创建新线程,事务上下文不传递 -
事务传播行为配置错误 :如
PROPAGATION_NOT_SUPPORTED
面试题4:如何查看JDK动态代理生成的类文件?
参考答案:
两种方式:
arduino
// 方式1:代码中设置系统属性(必须在生成代理前设置)
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 方式2:JVM启动参数
// java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true MyApp
生成的 .class 文件保存在当前工作目录下的 com/sun/proxy/ 中。
查看方式:
bash
# 反汇编查看
javap -c com.sun.proxy.$Proxy0
# 反编译查看
javap -p com.sun.proxy.$Proxy0
# 使用IDEA或JD-GUI查看反编译代码
CGLIB查看生成类:
arduino
// 设置系统属性
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
"/path/to/output");
面试题5:Proxy.newProxyInstance的类加载器为什么要用目标类的类加载器?
参考答案:
因为代理类需要:
- 加载目标接口:代理类要实现这些接口
- 类加载器兼容性:接口的类加载器必须与代理类的类加载器兼容
使用目标类加载器的原因:
- 目标类加载器已经加载了目标类,大概率也能加载接口
- 避免
ClassNotFoundException - 避免
ClassCastException(不同类加载器加载的同一类不兼容)
在复杂类加载环境(如OSGi、Tomcat)中,类加载器选择错误会导致:
bash
java.lang.ClassCastException:
com.sun.proxy.$Proxy0 cannot be cast to UserService
面试题6:CGLIB为什么不能代理final类?
参考答案:
CGLIB通过生成目标类的子类来实现代理:
scala
public class OrderService$$EnhancerByCGLIB extends OrderService {
// 重写方法并添加拦截逻辑
}
Java语言规范规定:
final类不能被继承final方法不能被重写
因此:
- final类 → CGLIB无法生成子类 → 无法代理
- final方法 → CGLIB无法重写 → 方法不被拦截
解决方案:
- 需要代理的类不要声明为final
- 需要代理的方法不要声明为final
- 如果必须使用final类,考虑JDK代理(基于接口)或AspectJ
面试题7:JDK动态代理和CGLIB在Spring中的选择策略是什么?
参考答案:
Spring AOP的选择策略:
kotlin
Spring AOP代理选择逻辑:
目标类有接口?
├── 是 → 使用JDK动态代理(默认)
│ └── 代理接口方法
│ └── 注入时按接口类型注入
│
└── 否 → 使用CGLIB代理
└── 生成目标类的子类
└── 可以按类类型注入
Spring Boot 2.x+ 默认行为变更:
- 默认使用CGLIB(spring.aop.proxy-target-class=true)
- 原因:
1. JDK代理只能代理接口,按类型注入可能失败
2. CGLIB代理类,注入更灵活
3. CGLIB性能更好
强制使用JDK代理:
@SpringBootApplication
@EnableAspectJAutoProxy(proxyTargetClass = false)
public class Application { }
强制使用CGLIB:
@EnableAspectJAutoProxy(proxyTargetClass = true)
面试题8:动态代理和反射的关系是什么?
参考答案:
objectivec
动态代理 vs 反射:
反射(Reflection):
├── Java运行时检查/修改类和对象行为的能力
├── 核心类:Class、Method、Field、Constructor
├── 用途:动态调用方法、访问字段、创建实例
└── 性能开销大(绕过编译时检查)
动态代理(Dynamic Proxy):
├── 运行时生成代理类的技术
├── 两种实现:JDK Proxy、CGLIB
├── JDK代理依赖反射调用目标方法
└── CGLIB通过FastClass避免反射
关系:
- JDK动态代理底层使用反射调用目标方法
- CGLIB代理底层使用字节码技术,不依赖反射
- 反射是"能力",动态代理是"应用"
面试题9:为什么CGLIB有两个类(Enhancer和FastClass)?
参考答案:
CGLIB生成两个类的分工:
php
代理类(*$$EnhancerByCGLIB):
├── 继承目标类
├── 重写方法,插入拦截逻辑
├── 持有MethodInterceptor回调
└── 负责"拦截"
FastClass(*$$FastClassByCGLIB):
├── 不继承目标类
├── 为每个方法分配索引
├── 通过switch(index)直接调用方法
└── 负责"高效调用"
为什么分离?
1. 职责分离:代理类负责AOP逻辑,FastClass负责高效调用
2. 性能优化:FastClass可被复用(如invokeSuper时)
3. 灵活性:可以只生成FastClass而不生成代理(如方法调用优化)
面试题10:手写一个极简的JDK动态代理实现
参考答案:
typescript
import java.lang.reflect.*;
/**
* 极简JDK动态代理实现(模拟核心逻辑)
*/
public class MiniProxy {
/**
* 模拟Proxy.newProxyInstance
*/
@SuppressWarnings("unchecked")
public static <T> T newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
// 实际实现会生成字节码,这里用反射模拟
// 真实实现:生成$Proxy0类并加载
// 简化的模拟实现(仅用于理解原理)
return (T) java.lang.reflect.Proxy.newProxyInstance(
loader, interfaces, h);
}
/**
* 模拟InvocationHandler
*/
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
/**
* 模拟生成的代理类结构(伪代码)
*/
/*
public final class $Proxy0 extends Proxy implements UserService {
private static Method m1; // saveUser方法
static {
m1 = UserService.class.getMethod("saveUser", String.class);
}
public $Proxy0(InvocationHandler h) {
super(h);
}
public void saveUser(String name) {
try {
super.h.invoke(this, m1, new Object[]{name});
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
}
*/
// 测试
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = newProxyInstance(
target.getClass().getClassLoader(),
new Class<?>[]{UserService.class},
(proxyObj, method, methodArgs) -> {
System.out.println("[代理] 调用: " + method.getName());
return method.invoke(target, methodArgs);
}
);
proxy.saveUser("测试用户");
}
}
interface UserService {
void saveUser(String name);
}
class UserServiceImpl implements UserService {
@Override
public void saveUser(String name) {
System.out.println("保存用户: " + name);
}
}
小结
动态代理是Java框架的核心基础设施,理解其原理对掌握Spring AOP、MyBatis、Dubbo等框架至关重要。
核心要点回顾
swift
动态代理核心知识图谱:
┌─────────────────┐
│ 动态代理技术 │
└────────┬────────┘
│
┌────────────────┼────────────────┐
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ JDK动态代理 │ │ CGLIB代理 │
│ (基于接口) │ │ (基于继承) │
└───────┬───────┘ └───────┬───────┘
│ │
┌───────┴───────┐ ┌───────┴───────┐
│ ProxyGenerator│ │ ASM字节码框架 │
│ 生成$Proxy0 │ │ 生成子类 │
│ 反射调用目标 │ │ FastClass优化 │
└───────────────┘ └───────────────┘
│ │
└───────────────┬───────────────┘
│
▼
┌───────────────┐
│ 应用场景 │
│ - Spring AOP │
│ - MyBatis │
│ - Dubbo RPC │
│ - 事务管理 │
└───────────────┘
选择建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 目标类有接口 | JDK动态代理 | Spring默认,无额外依赖 |
| 目标类无接口 | CGLIB | 可代理类方法 |
| 追求极致性能 | AspectJ | 编译时织入,无代理开销 |
| 运行时字节码操作 | Javassist/ASM | 灵活控制字节码生成 |
| 简单日志/权限 | JDK动态代理 | 简单够用 |
| 复杂AOP场景 | CGLIB + Spring AOP | 功能完善,生态成熟 |
注意事项
- final类/方法:CGLIB无法代理,优先使用接口
- 同类内部调用 :代理会失效,使用
AopContext.currentProxy()或拆分类 - 类加载器:确保代理类加载器能加载目标接口
- 性能敏感场景:考虑AspectJ编译时织入
- 调试技巧:设置系统属性保存生成的代理类文件
此文原创,转载请注明出处。