Java 动态代理:从入门到实战
·
动态代理是 Java 中非常核心的设计模式(代理模式的进阶),简单说就是在程序运行时动态生成代理类,而非编译期提前写死,能灵活地为目标对象的方法增加额外逻辑(如日志、权限、事务),且无需修改目标类代码,是 Spring AOP 等框架的底层核心。
一、核心概念(通俗理解)
- 目标对象:真正执行业务逻辑的对象(比如
UserService)。 - 代理对象:动态生成的 “包装类”,负责调用目标对象方法,并在调用前后加额外逻辑。
- 核心接口 / 类:
InvocationHandler:代理逻辑的核心接口,需实现invoke()方法(这里写额外逻辑)。Proxy:JDK 提供的工具类,通过newProxyInstance()动态生成代理对象。
注意:JDK 动态代理只能代理实现了接口的类;如果要代理无接口的类,需用 CGLIB(基于继承)。
二、极简实战代码(JDK 动态代理)
以 “给用户服务的方法加日志” 为例,完整可运行代码:
java
运行
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 1. 定义业务接口(JDK动态代理必须有接口)
interface UserService {
void addUser(String username);
void deleteUser(String username);
}
// 2. 实现目标类(真正的业务逻辑)
class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("新增用户:" + username);
}
@Override
public void deleteUser(String username) {
System.out.println("删除用户:" + username);
}
}
// 3. 实现InvocationHandler,编写代理逻辑
class LogInvocationHandler implements InvocationHandler {
// 目标对象(被代理的对象)
private final Object target;
// 构造方法传入目标对象
public LogInvocationHandler(Object target) {
this.target = target;
}
/**
* 代理核心方法:每次调用代理对象的方法,都会执行这里
* @param proxy 代理对象本身(一般不用)
* @param method 被调用的方法(如addUser)
* @param args 方法参数(如username)
* @return 方法执行结果
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:调用目标方法前加日志
System.out.println("[日志] 执行方法:" + method.getName() + ",参数:" + (args != null ? args[0] : "无"));
// 调用目标对象的真实方法
Object result = method.invoke(target, args);
// 后置增强:调用目标方法后加日志
System.out.println("[日志] 方法" + method.getName() + "执行完成");
return result;
}
}
// 4. 测试动态代理
public class DynamicProxyDemo {
public static void main(String[] args) {
// 1. 创建目标对象
UserService target = new UserServiceImpl();
// 2. 创建代理处理器
InvocationHandler handler = new LogInvocationHandler(target);
// 3. 动态生成代理对象(核心方法)
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 目标对象实现的接口
handler // 代理逻辑处理器
);
// 4. 调用代理对象的方法(会触发invoke())
proxy.addUser("张三");
proxy.deleteUser("李四");
}
}
三、代码运行结果
plaintext
[日志] 执行方法:addUser,参数:张三
新增用户:张三
[日志] 方法addUser执行完成
[日志] 执行方法:deleteUser,参数:李四
删除用户:李四
[日志] 方法deleteUser执行完成
四、核心关键点解释
- Proxy.newProxyInstance():
- 三个参数:类加载器(和目标对象一致)、目标对象的接口数组、InvocationHandler 实现类。
- 返回值是实现了目标接口的代理对象,可直接强转为目标接口类型。
- invoke () 方法:
- 所有代理对象的方法调用都会转发到这里。
method.invoke(target, args)是真正调用目标对象的方法,缺一不可。
- 应用场景:
- Spring AOP(面向切面编程):核心就是动态代理,实现日志、事务、权限的统一管理。
- RPC 框架(如 Dubbo):代理远程服务接口,隐藏网络通信细节。
五、JDK 动态代理 vs CGLIB(补充)
表格
| 特性 | JDK 动态代理 | CGLIB 代理 |
|---|---|---|
| 底层实现 | 实现目标接口 | 继承目标类 |
| 适用场景 | 有接口的类 | 无接口的类 |
| 性能 | JDK8+ 后性能优于 CGLIB | 早期版本性能好,现在略逊 |
| 限制 | 不能代理类(只能代理接口) | 不能代理 final 类 / 方法 |
总结
- Java 动态代理的核心是运行时生成代理类,核心类是
Proxy(生成代理)和InvocationHandler(代理逻辑)。 - JDK 动态代理仅支持接口代理,无接口场景需用 CGLIB,Spring 默认自动切换两者。
- 动态代理是 AOP、RPC 等技术的底层基础,核心价值是无侵入式增强方法逻辑。
更多推荐




所有评论(0)