JDK动态代理实现原理与伪代码
2026/5/8 16:04:42 网站建设 项目流程

JDK动态代理主要基于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现,其核心是为接口在运行时动态创建代理类及其实例。根据其实现方式和应用场景,可以理解为一种统一的实现机制,但若从代理目标的角度细分,可分为基于接口的代理结合AOP框架的代理(后者是前者的高级应用)。

下面通过一个生活化的例子、基本原理、伪代码实现和记忆要点来详细讲解。

一、生活例子与基本原理

生活例子
想象你是一个明星(真实对象,即被代理对象),你的经纪公司(代理对象)负责处理所有外界对你的邀约。你(明星)和经纪公司都必须遵守一份《明星合作标准合同》(接口)。当有电影、广告来找你时,他们不直接联系你,而是联系你的经纪公司。经纪公司在把邀约转达给你(调用你的方法)之前,会先进行筛选、谈价、签保密协议(增强逻辑),事后再进行宣传、收款(增强逻辑)。这个“经纪公司”就是JDK动态代理为你创建的,它和你实现了同一份合同(接口),所以外界认为它就是“你”。

基本原理

  1. 接口约束:JDK动态代理要求被代理的目标对象必须至少实现一个接口。这是因为它动态生成的代理类会实现这个(些)接口。
  2. InvocationHandler:这是“增强逻辑”的编写处。你(开发者)需要实现这个接口,在它的invoke方法中定义代理逻辑(如经纪公司的筛选、谈价等),并在该方法内决定是否及如何调用原始目标对象的方法。
  3. Proxy类:这是JDK提供的“代理类工厂”。你调用Proxy.newProxyInstance方法,传入目标类的类加载器、目标对象实现的接口列表以及你编写的InvocationHandler实例。该方法会在运行时动态生成一个实现了指定接口的代理类的字节码,并实例化它。
  4. 方法调用:当客户端调用代理对象的任何方法时,这个调用都会被转发到InvocationHandler.invoke方法。在该方法内,你可以通过Method对象和args参数获知被调用的具体方法和参数,然后决定执行你的增强逻辑,并最终通过反射调用目标对象的原始方法。

二、伪代码实现

我们将模拟一个“用户服务”(UserService)的接口,并为其创建代理,在方法执行前后添加日志。

// 1. 定义业务接口 (明星的合同) public interface UserService { void addUser(String username); String getUserInfo(int id); } // 2. 真实对象,实现业务接口 (明星本人) public class UserServiceImpl implements UserService { @Override public void addUser(String username) { System.out.println("真实方法: 添加用户 " + username); // ... 实际的数据库操作 } @Override public String getUserInfo(int id) { System.out.println("真实方法: 获取用户信息,ID=" + id); return "用户" + id + "的信息"; } } // 3. 实现InvocationHandler,编写增强逻辑 (经纪公司的业务规则) import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { // 持有被代理的真实目标对象 private final Object target; public MyInvocationHandler(Object target) { this.target = target; } /** * 所有对代理对象方法的调用,都会路由到此方法 * @param proxy 代理对象本身 (通常很少直接使用) * @param method 被调用的方法对象 (通过反射获得) * @param args 调用方法时传入的参数 * @return 方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强:执行方法前的逻辑 (例如:权限检查、日志、事务开启) System.out.println("[JDK代理] 开始执行方法: " + method.getName() + ",参数: " + Arrays.toString(args)); // 调用真实目标对象的原始方法 Object result = method.invoke(target, args); // 后置增强:执行方法后的逻辑 (例如:日志、结果处理、事务提交/回滚) System.out.println("[JDK代理] 方法执行完毕,结果: " + result); return result; } } // 4. 客户端使用Proxy创建代理对象并调用 (制作经纪公司并让其接活) import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { // 创建真实目标对象 UserService realService = new UserServiceImpl(); // 创建InvocationHandler,将真实对象传入 InvocationHandler handler = new MyInvocationHandler(realService); // 使用Proxy类的静态方法创建代理对象 // 参数1:类加载器,通常用目标类的类加载器 // 参数2:代理类需要实现的接口列表 // 参数3:InvocationHandler实例 UserService proxyInstance = (UserService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), // 类加载器 realService.getClass().getInterfaces(), // 实现的接口数组 handler // 调用处理器 ); // 现在,proxyInstance就是动态生成的代理对象 // 调用代理对象的方法,实际上会执行handler.invoke() proxyInstance.addUser("张三"); System.out.println("---------------"); String info = proxyInstance.getUserInfo(1001); System.out.println("客户端收到: " + info); } }

运行上述伪代码,输出将类似于:

[JDK代理] 开始执行方法: addUser,参数: [张三] 真实方法: 添加用户 张三 [JDK代理] 方法执行完毕,结果: null --------------- [JDK代理] 开始执行方法: getUserInfo,参数: [1001] 真实方法: 获取用户信息,ID=1001 [JDK代理] 方法执行完毕,结果: 用户1001的信息 客户端收到: 用户1001的信息

三、如何记忆与要点总结

  1. 一个核心限制只能代理接口。这是JDK动态代理与CGLIB(可代理类)最根本的区别。
  2. 两个关键角色
    • InvocationHandler(调用处理器)增强逻辑的容器。记住它是你写业务增强代码(如日志、事务)的地方,所有方法调用都汇聚到它的invoke方法。
    • Proxy(代理工厂)代理对象的生成器。记住它的newProxyInstance方法,需要三个参数:类加载器、接口数组、InvocationHandler
  3. 三步创建流程
    1. 定义或拥有接口和它的实现类(目标对象)。
    2. 编写InvocationHandler实现类,在invoke中编织增强逻辑,并通过反射调用原始方法。
    3. 调用Proxy.newProxyInstance(),传入必要的参数,获得代理对象。
  4. 应用场景联想:它广泛应用于AOP(面向切面编程)RPC框架调用声明式事务管理MyBatis的Mapper接口实现等场景。在这些场景中,框架利用动态代理在方法调用前后自动插入通用逻辑(如日志、事务、网络通信)。

四、总结

JDK动态代理是一种基于接口的、在运行时生成代理类的强大机制。其本质是通过Proxy类合成一个实现了指定接口的代理类,并将所有方法调用委托给用户定义的InvocationHandler来处理。它的优点是无需为每个被代理类预先编写代理类,代码复用性高,符合面向接口编程的原则;缺点是只能代理接口,对于没有接口的类无能为力。

在实际的Spring AOP中,如果目标对象实现了接口,默认就会使用JDK动态代理来创建AOP代理;如果目标对象没有实现接口,则会使用CGLIB来生成基于子类的代理。理解JDK动态代理是深入掌握Spring AOP、RPC以及许多Java高级框架的基础。


参考来源

  • Spring常用注解(绝对经典)
  • JDK动态代理入门
  • Mybatis 实现原理之 JDK动态代理和XML语句执行
  • 【Spring Boot】Spring AOP动态代理,以及静态代理
  • JVAV设计模式-代理模式实现原理伪代码
  • 基于JDK动态代理实现的Spring AOP源码学习

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询