1、简述
Java 动态代理(Dynamic Proxy)是 Java 反射体系的重要能力之一,它能够在运行时动态生成代理类,从而无需在编译期就定义代理逻辑。动态代理广泛应用于 AOP(Aspect-Oriented Programming)、RPC 框架、ORM 框架、监控埋点、权限控制等领域。
本文将从原理、实现方式、关键特性以及实际应用角度系统介绍 Java 动态代理,并提供可直接运行的实践示例代码。

2、什么是动态代理?
代理模式允许开发者为目标对象提供一个“代理”,由该代理来控制对目标对象的访问。与静态代理相比,动态代理无需手动编写代理类,而是由 JVM 在运行时生成。
Java 提供了两种主流的动态代理方式:
🔥 JDK 动态代理(基于接口) 依赖 java.lang.reflect.Proxy 和 InvocationHandler,要求目标类必须实现接口。
🔥 CGLIB 动态代理(基于继承)
通过生成子类字节码来完成代理,无需接口,但不能代理 final 类或 final 方法。
JDK 动态代理原理解析
JDK 动态代理基于以下两个核心组件:
InvocationHandler
一个回调接口,用于接管代理对象对目标方法的执行。
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
Proxy
用于动态生成代理类字节码。
3、JDK 动态代理实践用例
以下示例展示了如何使用 Java 自带的动态代理机制为业务接口添加日志功能。
3.1 定义业务接口与实现类
public interface OrderService {
void createOrder(String userId, String productId);
}
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String userId, String productId) {
System.out.println("正在创建订单:userId = " + userId + ", productId = " + productId);
}
}
3.2 编写动态代理(日志增强)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoggingInvocationHandler implements InvocationHandler {
private final Object target;
public LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[LOG] 调用方法:" + method.getName());
if (args != null) {
for (Object arg : args) {
System.out.println("[LOG] 参数:" + arg);
}
}
Object result = method.invoke(target, args);
System.out.println("[LOG] 方法执行完成:" + method.getName());
return result;
}
}
3.3 创建代理对象
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
OrderService orderService = new OrderServiceImpl();
OrderService proxy = (OrderService) Proxy.newProxyInstance(
orderService.getClass().getClassLoader(),
orderService.getClass().getInterfaces(),
new LoggingInvocationHandler(orderService)
);
proxy.createOrder("U1001", "P2002");
}
}
3.4 输出效果
[LOG] 调用方法:createOrder
[LOG] 参数:U1001
[LOG] 参数:P2002
正在创建订单:userId = U1001, productId = P2002
[LOG] 方法执行完成:createOrder
4、CGLIB 动态代理实践示例
当业务类没有实现接口时,可以使用 CGLIB(如 Spring AOP 内部使用)。
Maven 依赖(如未由 Spring 自动提供)
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
示例代码
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibLoggingProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[CGLIB LOG] 调用:" + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("[CGLIB LOG] 执行完成:" + method.getName());
return result;
}
public static <T> T createProxy(Class<T> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(new CglibLoggingProxy());
return (T) enhancer.create();
}
}
public class PayService {
public void pay(int amount) {
System.out.println("支付金额:" + amount);
}
}
public class CglibDemo {
public static void main(String[] args) {
PayService proxy = CglibLoggingProxy.createProxy(PayService.class);
proxy.pay(300);
}
}
5、总结
动态代理是 Java 中极为重要的底层机制,具有以下优势:
🔥 无需手写代理类,减少重复代码
🔥 增强逻辑可集中处理,符合 AOP 设计思想
🔥 适用于多种框架和中间件的底层实现
理解动态代理,不仅能帮助我们更好地理解 Spring、MyBatis 等框架,也能在实际业务开发中灵活实现日志、监控、权限等横切功能。
动态代理常见应用场景:
| 领域 | 说明 |
|---|---|
| AOP(面向切面编程) | 日志、缓存、事务、性能分析等切面逻辑 |
| RPC 框架 | 如 Dubbo:通过代理调用远程服务 |
| ORM 框架 | MyBatis Mapper 动态代理执行 SQL |
| Spring 事务管理 | 利用代理在方法前后加入事务切面 |
| 监控 & 埋点系统 | 收集接口调用信息 |
如果你正在构建一个可扩展的系统,动态代理机制绝对值得深入掌握。