Java 动态代理概述
在 Java 开发中,代理模式是设计模式之一,而动态代理作为代理模式的进阶形式,在框架开发(如 Spring AOP)、日志记录、权限控制等场景中发挥着关键作用。本文将从核心概念出发,拆解两种主流动态代理的实现逻辑,并分析其适用场景。
Java 动态代理是在运行时通过反射机制动态生成代理类的技术,无需编译期预定义。主要包含 JDK 动态代理和 CGLIB 动态代理两种方式。JDK 动态代理基于接口,依赖原生 API,要求目标类必须实现接口;CGLIB 动态代理基于子类,需引入第三方库,可代理任意类(除 final 类)。两者均用于解耦横切逻辑,如 Spring AOP、日志记录、权限控制等场景。选择时若目标类有接口优先用 JDK,无接口则选 CGLIB。

在 Java 开发中,代理模式是设计模式之一,而动态代理作为代理模式的进阶形式,在框架开发(如 Spring AOP)、日志记录、权限控制等场景中发挥着关键作用。本文将从核心概念出发,拆解两种主流动态代理的实现逻辑,并分析其适用场景。
动态代理指在程序运行时,通过反射机制动态生成代理类,而非在编译期预先定义。其核心价值在于:无需为每个目标类手动编写代理类,即可统一为多个目标类添加横切逻辑(如日志、事务、异常处理),降低代码耦合度。
动态代理包含三个核心角色:
Java 中动态代理主要有两种实现方式:JDK 动态代理(原生 API)和 CGLIB 动态代理(第三方库),二者在原理和使用上存在显著差异。
JDK 动态代理依赖 java.lang.reflect 包下的 Proxy 和 InvocationHandler 接口,要求目标类必须实现至少一个接口。运行时,JVM 会动态生成一个实现目标接口的代理类,代理类的方法调用会转发到 InvocationHandler 的 invoke 方法中,在该方法中可嵌入增强逻辑并调用目标方法。
// 1. 定义接口
public interface UserService {
void addUser(String name);
}
// 2. 实现目标类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户:" + name);
}
}
// 3. 实现 InvocationHandler(增强逻辑)
public class LogInvocationHandler implements InvocationHandler {
private Object target; // 目标类引用
public LogInvocationHandler(Object target) {
this.target = target;
}
// 代理类的所有方法调用都会触发 invoke
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强逻辑:前置日志
System.out.println("方法" + method.getName() + "开始执行,参数:" + Arrays.toString(args));
// 调用目标方法
Object result = method.invoke(target, args);
// 增强逻辑:后置日志
System.out.println("方法" + method.getName() + "执行结束");
return result;
}
}
// 4. 生成代理类并测试
public class JdkProxyTest {
public static void main(String[] args) {
// 目标对象
UserService target = new UserServiceImpl();
// 生成代理对象(需传入类加载器、目标接口、InvocationHandler)
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogInvocationHandler(target)
);
// 调用代理方法
proxy.addUser("张三");
}
}
CGLIB(Code Generation Library)是一个第三方字节码生成库,通过生成目标类的子类作为代理类,无需目标类实现接口。其核心是 MethodInterceptor 接口,代理类的方法调用会被拦截到 intercept 方法中,在此处嵌入增强逻辑并调用目标方法。
<!-- Maven 依赖 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
// 1. 目标类(无需实现接口)
public class OrderService {
public void createOrder(String orderId) {
System.out.println("创建订单:" + orderId);
}
}
// 2. 实现 MethodInterceptor(增强逻辑)
public class LogMethodInterceptor implements MethodInterceptor {
// 拦截代理类方法调用
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 增强逻辑:前置日志
System.out.println("方法" + method.getName() + "开始执行,参数:" + Arrays.toString(args));
// 调用目标方法(推荐用 methodProxy.invokeSuper,避免递归调用)
Object result = methodProxy.invokeSuper(o, args);
// 增强逻辑:后置日志
System.out.println("方法" + method.getName() + "执行结束");
return result;
}
}
// 3. 生成代理类并测试
public class CglibProxyTest {
public static void main(String[] args) {
// CGLIB 核心类:Enhancer
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(OrderService.class);
// 设置方法拦截器
enhancer.setCallback(new LogMethodInterceptor());
// 生成代理对象(子类实例)
OrderService proxy = (OrderService) enhancer.create();
// 调用代理方法
proxy.createOrder("ORDER_001");
}
}
| 对比维度 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|
| 依赖 | JDK 原生 API(无第三方依赖) | 需引入 CGLIB 库 |
| 代理原理 | 实现目标接口 | 生成目标类子类 |
| 目标类要求 | 必须实现接口 | 无接口要求(不能是 final 类) |
| 方法限制 | 仅代理接口中的方法 | 不能代理 final 方法 |
| 性能(JDK 8+) | 生成快,调用效率高 | 生成慢,调用效率略低 |
动态代理是 Java 中'解耦横切逻辑'的核心技术,JDK 动态代理和 CGLIB 各有适用场景:若目标类已实现接口,优先选择 JDK 动态代理(轻量化、无依赖);若目标类无接口或需代理类的所有方法,选择 CGLIB。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online