jdk动态代理通过proxy.newproxyinstance创建接口代理对象,需类加载器、接口数组和invocationhandler三要素,仅支持接口代理,底层生成$proxy开头的代理类并统一由invoke拦截方法调用。

Java 接口的动态代理实现 AOP 切面拦截,核心在于用 Proxy.newProxyInstance 创建接口代理对象,并通过 InvocationHandler 统一调度前置、目标、后置与异常逻辑。它天然面向接口、无字节码生成开销,适合高频调用场景,性能优于 CGLIB(尤其在小对象、短方法上)。
必须基于接口,且目标类要实现该接口
这是 JDK 动态代理的硬性前提。JVM 只能为接口生成代理类($Proxy0 这类),不能为普通类生成。所以:
- 定义清晰的业务接口(如
OrderService),而非直接代理OrderServiceImpl类本身 - 目标实现类(
OrderServiceImpl)必须implements OrderService - 代理对象类型只能是接口类型,调用方也需依赖接口编程,否则编译不通过
用 InvocationHandler 封装可插拔的切面逻辑
不要把日志、权限等逻辑写死在 invoke 方法里。应将增强行为抽象为独立组件:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 定义切面接口,例如
Aspect,含before(Method, Object[])、afterReturning(Method, Object, Object[])等方法 - 编写具体切面类:如
LoggingAspect、MetricsAspect,各自只关心一件事 - 在
invoke中按顺序调用已注册的切面,支持链式执行与短路(如权限失败直接 return)
透传参数与返回值,避免反射性能损耗
虽然用反射调用目标方法不可避免,但可减少冗余操作提升效率:
- 提前缓存
Method对象(比如用ConcurrentHashMap<string method></string>按全限定名索引),避免每次method.invoke()前重复查找 - 参数数组
Object[] args直接透传,不 clone、不包装;返回值原样返回,不做无谓转换 - 对异常统一捕获并分类处理(
throwable instanceof RuntimeException→ afterThrowing;否则 → afterFinally),避免多次instanceof判断
代理对象应复用,避免频繁创建
每次调用 Proxy.newProxyInstance 都会触发类生成、加载、验证,开销不小。实际使用中:
- 一个目标实例 + 一套切面组合,对应唯一代理对象,应作为单例或 Bean 管理(Spring 默认即如此)
- 若需不同切面组合,可构建代理工厂,按 key 缓存不同配置的代理实例,而非每次都 new
- 注意线程安全:
InvocationHandler实例本身应是无状态或线程安全的,避免共享可变字段
不复杂但容易忽略。关键不在“能不能代理”,而在于切面是否真正解耦、参数是否零拷贝、代理是否被合理复用——这三点决定了它是不是“高性能”的 AOP。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










