Java 代理模式详解
代理在不改目标类的前提下织入横切逻辑(日志、事务、鉴权)。Java 里分编译期确定的静态代理与运行期生成字节码的动态代理,Spring AOP 与 RPC 客户端都建立在这套机制上。
核心概念
静态代理:手写代理类实现同一接口,委托目标对象;接口变更时代理也要改,维护成本高。JDK 动态代理:基于接口,Proxy.newProxyInstance + InvocationHandler,在 invoke 里前后增强。CGLIB:继承目标类生成子类,覆盖非 final 方法;无接口也可代理,但不能代理 final 类/方法。
关键机制与实践
JDK 代理要求目标实现接口;Spring 默认有接口用 JDK,无接口用 CGLIB(Boot 2.x 后 CGLIB 更常见)。InvocationHandler.invoke 里通过 method.invoke(target, args) 调用真实方法,此处即反射调用点。Self-invocation(类内部 this.foo())不会走代理,是 @Transactional 失效经典原因之一。
1 | SmsService proxy = (SmsService) Proxy.newProxyInstance( |
常见误区与小结
- 认为 CGLIB 一定比 JDK 慢(现代版本差距已缩小,视场景而定)。
- 忽略
equals/hashCode在代理对象上的行为差异。 - 在 handler 里忘记调用目标方法导致「空增强」。
读懂代理,就读懂了 Spring 事务、缓存、Feign 等「看起来魔法」的入口。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Dai Wei!
评论

