快速理解动态代理
-
什么是动态代理(Java核心技术卷1的解释)
动态代理是一种运行时生成代理对象的技术,其本质是通过字节码增强在不修改原始类代码的前提下,动态拦截并扩展目标对象的行为。它通过代理对象对原始方法的调用进行拦截,并在方法执行前后注入自定义逻辑(如日志、事务、权限校验等),实现逻辑与业务解耦。 -
实现原理
动态代理的核心机制基于以下两个组件:
• InvocationHandler
接口:定义代理逻辑的拦截器,通过invoke()
方法统一处理目标方法的调用。在此方法中,开发者可插入前置/后置逻辑,并通过反射调用原始方法。
• Proxy
类:用于动态生成代理对象。通过Proxy.newProxyInstance()
方法,根据目标接口和InvocationHandler
生成代理类的字节码并实例化。
示例流程:
-
定义目标接口(如
UserService
)及其实现类; -
实现
InvocationHandler
,在invoke()
中添加增强逻辑; -
使用
Proxy
动态生成代理对象,替代原始对象对外提供服务。 -
与静态代理的区别
- 技术实现分类
• JDK动态代理:
基于接口实现,要求目标类必须实现至少一个接口。通过反射机制生成代理对象,适用于接口驱动的场景(如Spring AOP默认实现)。
• CGLib动态代理:
基于继承实现,通过修改字节码生成目标类的子类作为代理。可代理无接口的类,但无法代理final
类或方法(常见于Spring对非接口类的增强)。
- 应用场景
- AOP(面向切面编程):
实现日志记录、事务管理、性能监控等横切关注点,如Spring通过动态代理实现@Transactional
注解。 - 远程调用(RPC):
代理对象封装网络通信细节,使远程服务调用对客户端透明(如Dubbo的消费者代理)。 - 安全控制:
在方法调用前进行权限校验,拦截非法请求(如Spring Security的动态代理拦截)。 - 延迟加载:
代理对象按需加载资源,减少初始化开销(如Hibernate的懒加载实现)。
- 性能与限制
• 性能开销:动态代理依赖反射和字节码生成,调用效率略低于直接调用(可通过缓存代理类优化)。
• 使用限制:
-
JDK代理无法代理类,CGLib无法代理
final
方法; -
需注意代理链的层级管理,避免过度代理导致复杂度上升。