动态代理(Dynamic Proxy)是一种在程序运行时动态生成代理对象的技术,用于在不修改原始类代码的前提下,拦截并增强目标对象的方法调用。其核心价值在于实现逻辑与业务解耦,广泛应用于日志记录、事务管理、权限控制等场景。
⚙️ 核心概念与原理
- 代理的本质
- 静态代理:需预先编写代理类,每个目标类需对应一个代理类,代码冗余度高。
- 动态代理:在运行时通过反射或字节码技术(如JDK Proxy、CGLIB)动态生成代理类,无需手动编码。
- 工作原理
- 拦截机制:代理对象拦截所有方法调用,转发给关联的处理器(如
InvocationHandler
或MethodInterceptor
)。 - 增强逻辑:在目标方法执行前后插入自定义操作(如日志记录、权限校验)。
- 拦截机制:代理对象拦截所有方法调用,转发给关联的处理器(如
🛠️ 实现方式(以Java为例)
JDK动态代理(基于接口)
- 要求:目标类必须实现至少一个接口。
- 核心类:
Proxy
:生成代理对象(Proxy.newProxyInstance()
)。InvocationHandler
:定义拦截逻辑(invoke()
方法)。
- 示例:
public class LogHandler implements InvocationHandler { private Object target; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = method.invoke(target, args); // 调用目标方法 System.out.println("After method: " + method.getName()); return result; } } // 生成代理对象 Service proxy = (Service) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new LogHandler(target) );
CGLIB动态代理(基于继承)
- 要求:可代理普通类(无法代理
final
类或方法)。 - 核心类:
Enhancer
:生成代理类(继承目标类)。MethodInterceptor
:定义拦截逻辑(intercept()
方法)。
- 示例:
public class CglibInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before method: " + method.getName()); Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)方法 System.out.println("After method: " + method.getName()); return result; } } // 生成代理对象 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(TargetClass.class); enhancer.setCallback(new CglibInterceptor()); TargetClass proxy = (TargetClass) enhancer.create();
JDK代理 vs CGLIB代理对比
维度 | JDK动态代理 | CGLIB动态代理 |
---|---|---|
代理对象要求 | 必须实现接口 | 可代理任意普通类(非final ) |
实现机制 | 反射 | 字节码增强(ASM框架) |
性能 | 调用速度较慢(反射开销) | 生成快,调用快(直接调用) |
依赖 | Java原生支持 | 需引入CGLIB库 |
⭐ 典型应用场景
- 面向切面编程(AOP)
- 日志记录:在方法调用前后自动记录参数、返回值。
- 事务管理:方法执行前开启事务,执行后提交或回滚(如Spring
@Transactional
)。 - 权限控制:拦截方法调用,校验用户权限。
- 框架集成
- Spring AOP:默认使用JDK代理(接口)或CGLIB(无接口类)实现切面。
- MyBatis:动态代理Mapper接口,自动生成SQL执行逻辑。
- RPC框架(如Dubbo):代理远程服务接口,封装网络通信细节。
- 性能优化
- 延迟加载:代理对象按需加载资源(如Hibernate懒加载)。
- 缓存管理:方法调用前查询缓存s,命中则直接返回,避免重复计算。
⚖️ 优缺点分析
优点 | 缺点 |
---|---|
无侵入性:不修改目标类代码,实现功能增强。 | 性能开销:反射或字节码生成导致调用速度略低于直接调用。 |
解耦设计:分离核心业务与横切关注点(如日志、事务)。 | 使用限制:JDK代理需接口,CGLIB无法代理final 方法。 |
灵活扩展:动态调整代理逻辑,适应多变需求。 | 复杂度:代理链过长可能增加调试难度。 |
💎 总结
动态代理是运行时动态生成代理对象的核心技术,通过拦截方法调用实现功能增强,其价值在于:
- 解耦业务与非功能性需求(如日志、事务),提升代码可维护性;
- 支撑主流框架(如Spring AOP、MyBatis),简化开发流程;
- 扩展性强,可灵活适应复杂业务场景。
⚠️ 使用建议:优先选择JDK代理(目标类有接口),无接口时用CGLIB;避免过度代理导致性能下降,可通过缓存代理类优化效率。