java动态代理无法运行时替换目标对象,但可通过让invocationhandler持有可变目标引用(如atomicreference)并提供setter实现“动态切换”;或采用代理工厂+supplier模式按需获取目标;cglib同理需在intercept中动态选择目标实例。

Java 动态代理本身不支持在运行时替换被代理的目标对象实例——代理对象一旦创建,其内部持有的目标对象(通常由 InvocationHandler 持有)是固定的。但你可以通过设计让代理“看起来”能动态切换目标,关键在于把目标对象的引用控制权交给 InvocationHandler,而不是写死在构造时。
让 InvocationHandler 持有可变的目标引用
标准做法中,InvocationHandler 构造时传入一个固定 target,之后所有方法调用都转发给它。要实现动态切换,只需把目标对象设为可修改的字段,并提供 setter 方法:
- 定义一个线程安全的、可更新的目标引用(例如用
AtomicReference<object></object>或加锁的普通字段) - 在
invoke方法中,每次调用都从该引用读取当前目标对象 - 外部可通过公开方法随时更新这个引用,后续调用即自动作用于新目标
避免直接替换 Proxy 实例
不要试图修改 Proxy.newProxyInstance 返回的代理对象本身——它是一个不可变的 JDK 生成类实例,没有 API 支持“换 target”。强行反射修改内部字段不仅脆弱(JDK 内部结构可能变化),且在 Java 9+ 模块系统下会被模块限制拦截。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
更实用的替代方案:代理工厂 + 懒加载目标
如果目标对象需要按需创建或频繁变更,推荐封装一层代理工厂:
- 代理处理器不直接持有目标实例,而是持有目标类型、构造参数或获取目标的 Supplier
-
invoke中按需调用supplier.get()获取当前目标(可带缓存、条件判断、上下文路由等逻辑) - 这样目标对象的生命周期、复用策略、切换时机完全由业务逻辑控制,代理层无感知
注意 CGLIB 的特殊性
CGLIB 代理基于继承,目标对象在 Enhancer.create() 时绑定,同样不可运行时更换。但它允许在 MethodInterceptor.intercept() 中动态决定调用哪个实例(只要该实例是同一父类类型)。所以和 JDK 代理一样,解法仍是把目标选择逻辑前移到 intercept 内部,而非修改代理对象本身。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










