JDK 动态代理从原理到实战案例
JDK 动态代理是 Java 语言自带的代理机制,它基于反射实现,允许在运行时动态生成代理类。必须基于接口实现(这是与 CGLIB 代理的主要区别)通过类动态生成代理对象通过接口定义方法增强逻辑代理类在程序运行时动态生成,无需手动编写动态代理的典型应用场景有:日志记录、性能监控、事务管理、权限控制等,它能有效降低代码耦合度,符合开闭原则。JDK 动态代理必须基于接口,我们首先定义明星的行为接口St
一、引言
在 Java 开发中,代理模式是一种常用的设计模式,它能在不修改原始类代码的前提下对方法进行增强。而 JDK 动态代理作为 JDK 原生支持的代理实现方式,在框架开发和业务增强中有着广泛应用。本文将通过一个完整案例,带大家掌握 JDK 动态代理的实现原理与使用方法。
二、什么是jdk动态代理
JDK 动态代理是 Java 语言自带的代理机制,它基于反射实现,允许在运行时动态生成代理类。其核心特点包括:
- 必须基于接口实现(这是与 CGLIB 代理的主要区别)
- 通过
java.lang.reflect.Proxy类动态生成代理对象 - 通过
InvocationHandler接口定义方法增强逻辑 - 代理类在程序运行时动态生成,无需手动编写
动态代理的典型应用场景有:日志记录、性能监控、事务管理、权限控制等,它能有效降低代码耦合度,符合开闭原则。
三、实战案例:明星代理系统
下面我们通过一个 "明星代理" 案例来理解 JDK 动态代理的实现过程。场景需求:明星(目标对象)的演出活动需要经纪人(代理对象)提前做准备工作(方法增强)。
1. 定义接口(核心前提)
JDK 动态代理必须基于接口,我们首先定义明星的行为接口Star:
package com.heaboy.proxy;
public interface Star {
String sing(); // 唱歌方法
void dance(); // 跳舞方法
}
2. 实现目标类
创建实现Star接口的具体明星类MyStar,这是我们需要增强的目标对象:
package com.heaboy.proxy;
public class MyStar implements Star {
private String name;
// 构造方法初始化明星姓名
public MyStar(String name) {
this.name = name;
}
@Override
public String sing() {
System.out.println(name + "开始唱歌");
return "谢谢大家的掌声";
}
@Override
public void dance() {
System.out.println(name + "开始跳舞");
}
}
3. 编写代理工具类
这是实现动态代理的核心部分,我们需要通过Proxy类创建代理对象,并通过InvocationHandler定义增强逻辑:
package com.heaboy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class StarProxyUtil {
/**
* 创建明星代理对象
* @param target 目标明星对象
* @return 代理对象
*/
public static Star createProxy(MyStar target) {
// 1. 获取类加载器(通常使用当前类的类加载器)
ClassLoader loader = StarProxyUtil.class.getClassLoader();
// 2. 指定代理对象要实现的接口(与目标对象相同)
Class<?>[] interfaces = new Class[]{Star.class};
// 3. 定义代理逻辑(InvocationHandler匿名实现类)
InvocationHandler handler = new InvocationHandler() {
/**
* 代理对象的方法执行时会调用此方法
* @param proxy 代理对象本身(一般不使用)
* @param method 目标方法
* @param args 方法参数
* @return 目标方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法增强:根据不同方法执行不同的前置操作
if (method.getName().equals("sing")) {
System.out.println("经纪人:调试音响设备");
} else if (method.getName().equals("dance")) {
System.out.println("经纪人:准备舞蹈场地");
}
// 调用目标对象的原始方法
Object result = method.invoke(target, args);
// 可在此处添加后置增强逻辑(如演出收尾工作)
return result;
}
};
// 4. 动态生成并返回代理对象
return (Star) Proxy.newProxyInstance(loader, interfaces, handler);
}
}
4. 测试代理效果
编写测试类验证动态代理的执行结果:
package com.heaboy.proxy;
public class Test {
public static void main(String[] args) {
// 1. 创建目标对象
MyStar myStar = new MyStar("杨超越");
// 2. 获取代理对象(经纪人)
Star proxy = StarProxyUtil.createProxy(myStar);
// 3. 通过代理对象调用方法
proxy.dance(); // 调用跳舞方法
String response = proxy.sing(); // 调用唱歌方法
System.out.println(response);
}
}
执行结果:

三、JDK 动态代理核心原理分析
-
代理对象的生成:
Proxy.newProxyInstance()方法在运行时动态生成一个实现了指定接口的代理类字节码,并通过类加载器加载生成代理对象。 -
方法调用机制:当调用代理对象的方法时,不会直接执行目标方法,而是先调用
InvocationHandler的invoke()方法,在该方法中我们可以:- 执行前置增强逻辑(如权限校验、资源准备)
- 通过
method.invoke(target, args)调用目标对象的原始方法 - 执行后置增强逻辑(如日志记录、事务提交)
-
为什么必须基于接口:JDK 动态代理生成的代理类已经继承了
Proxy类,而 Java 是单继承机制,因此只能通过实现接口的方式生成代理对象。
四、总结与扩展
本文通过明星代理案例详细讲解了 JDK 动态代理的实现过程,核心要点包括:
- 必须定义接口,目标类实现该接口
- 通过
Proxy.newProxyInstance()生成代理对象 - 通过
InvocationHandler实现方法增强逻辑
在实际开发中,Spring AOP 的底层实现就大量使用了 JDK 动态代理(当目标对象实现接口时)。掌握动态代理思想,能帮助我们更好地理解框架原理,写出更灵活、低耦合的代码。
如果需要代理没有实现接口的类,可以考虑 CGLIB 代理(基于继承实现),大家可以对比学习两种代理方式的异同点,在实际项目中根据场景选择合适的方案。
更多推荐



所有评论(0)