动态代理(尤其是 Spring 动态代理)的核心价值是在不修改目标类源码的前提下,对目标方法进行增强 (如前置校验、后置处理、异常捕获、日志记录等),本质是面向切面编程(AOP) 的落地实现。下面结合实际开发场景,详细说明「什么时候需要用动态代理」以及「核心使用场景」。
一、核心使用时机(什么时候需要创建动态代理)
简单来说,只要满足以下任一条件,就适合用动态代理:
- 需要对方法进行 "无侵入式增强":不想修改目标类的源码(如第三方库的类、公司核心基础类),但要在方法执行前后添加额外逻辑;
- 需要统一处理多个类的通用逻辑:多个类 / 方法有重复的通用操作(如日志、事务、权限校验),希望抽离成公共逻辑,避免代码冗余;
- 需要动态控制方法执行:比如根据条件决定是否执行目标方法、修改方法入参 / 返回值、捕获方法异常并兜底;
- 需要解耦业务逻辑与非业务逻辑:将日志、事务、监控等 "横切逻辑" 与核心业务逻辑分离,符合「单一职责原则」。
反例:如果只是简单调用目标方法,没有任何额外增强逻辑,或只需要对单个方法做一次性修改,直接修改源码即可,无需动态代理(过度设计)。
二、动态代理的核心使用场景(附 Spring 实战示例)
以下是动态代理最常见的落地场景,全部基于 Spring 动态代理实现(也是 Spring 框架自身的核心应用场景):
场景 1:日志记录 / 接口监控
核心需求 :记录接口的调用时间、入参、返回值、耗时,方便排查问题和性能分析,且不侵入业务代码。实现方式:通过动态代理在方法执行前后添加日志逻辑。
示例(Spring 动态代理实现日志监控)
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
// 1. 前置日志增强(记录入参和开始时间)
class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("[监控] 方法 " + method.getName() + " 开始执行,入参:" + (args == null ? "无" : args[0]));
}
}
// 2. 后置日志增强(记录返回值和耗时)
class LogAfterAdvice implements AfterReturningAdvice {
private long startTime;
// 初始化开始时间(可结合 Around Advice 更优雅)
public void setStartTime(long startTime) {
this.startTime = startTime;
}
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
long cost = System.currentTimeMillis() - startTime;
System.out.println("[监控] 方法 " + method.getName() + " 执行完成,返回值:" + returnValue + ",耗时:" + cost + "ms");
}
}
// 3. 业务目标类
interface OrderService {
String createOrder(String orderNo);
}
class OrderServiceImpl implements OrderService {
@Override
public String createOrder(String orderNo) {
// 核心业务逻辑
try { Thread.sleep(100); } catch (InterruptedException e) {} // 模拟耗时
return "订单创建成功:" + orderNo;
}
}
// 4. 测试代码
public class LogProxyDemo {
public static void main(String[] args) {
// 创建目标对象
OrderService target = new OrderServiceImpl();
// 创建 Spring 代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
// 添加前置/后置增强
LogBeforeAdvice beforeAdvice = new LogBeforeAdvice();
LogAfterAdvice afterAdvice = new LogAfterAdvice();
proxyFactory.addAdvice(beforeAdvice);
proxyFactory.addAdvice((MethodInterceptor) invocation -> {
afterAdvice.setStartTime(System.currentTimeMillis());
return invocation.proceed(); // 执行目标方法
});
proxyFactory.addAdvice(afterAdvice);
// 创建代理对象并调用
OrderService proxy = (OrderService) proxyFactory.getProxy();
proxy.createOrder("ORDER_666");
}
}
执行结果:
[监控] 方法 createOrder 开始执行,入参:ORDER_666
[监控] 方法 createOrder 执行完成,返回值:订单创建成功:ORDER_666,耗时:101ms
场景 2:事务管理(Spring 声明式事务核心)
核心需求 :保证一组数据库操作要么全部成功(提交事务),要么全部失败(回滚事务),且事务逻辑与业务逻辑解耦。实现方式:Spring 通过动态代理在业务方法执行前开启事务,执行后提交事务,异常时回滚事务。
简化示例(模拟 Spring 事务代理)
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
// 1. 事务管理增强器
class TransactionAdvice implements MethodBeforeAdvice, ThrowsAdvice {
// 前置:开启事务
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("[事务] 开启数据库事务");
}
// 后置异常:回滚事务
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
System.out.println("[事务] 捕获异常:" + ex.getMessage() + ",回滚事务");
}
// 后置成功:提交事务
public void afterReturning(Method method, Object[] args, Object target, Object returnValue) {
System.out.println("[事务] 提交数据库事务");
}
}
// 2. 业务DAO类
class UserDAO {
public void insertUser(String username) {
System.out.println("执行插入用户:" + username);
// 模拟异常(触发事务回滚)
// throw new RuntimeException("插入失败:用户名重复");
}
}
// 3. 测试代码
public class TransactionProxyDemo {
public static void main(String[] args) {
UserDAO target = new UserDAO();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.setProxyTargetClass(true); // CGLIB代理(无接口)
proxyFactory.addAdvice(new TransactionAdvice());
// 添加后置成功增强
proxyFactory.addAdvice((AfterReturningAdvice) (returnValue, method, args, target1) -> {
((TransactionAdvice) proxyFactory.getAdvisors()[0].getAdvice()).afterReturning(method, args, target1, returnValue);
});
UserDAO proxy = (UserDAO) proxyFactory.getProxy();
try {
proxy.insertUser("张三");
} catch (Exception e) {
// 捕获异常,不影响程序执行
}
}
}
正常执行结果:
[事务] 开启数据库事务
执行插入用户:张三
[事务] 提交数据库事务
触发异常时结果:
[事务] 开启数据库事务
执行插入用户:张三
[事务] 捕获异常:插入失败:用户名重复,回滚事务
场景 3:权限校验
核心需求 :在执行敏感操作(如删除数据、修改配置)前,校验用户是否有对应的权限,无权限则拒绝执行。实现方式:通过动态代理在方法执行前校验权限,不满足则抛出异常。
示例
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
// 1. 权限校验增强
class PermissionAdvice implements MethodBeforeAdvice {
private String currentUserRole;
public PermissionAdvice(String currentUserRole) {
this.currentUserRole = currentUserRole;
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
// 检查方法是否需要管理员权限
if (method.getName().equals("deleteData")) {
if (!"ADMIN".equals(currentUserRole)) {
throw new SecurityException("权限不足:仅管理员可执行删除操作");
}
}
System.out.println("[权限校验] " + currentUserRole + " 用户执行 " + method.getName() + " 操作,校验通过");
}
}
// 2. 数据管理类
class DataManager {
public void queryData() {
System.out.println("执行数据查询");
}
public void deleteData() {
System.out.println("执行数据删除");
}
}
// 3. 测试代码
public class PermissionProxyDemo {
public static void main(String[] args) {
// 测试1:普通用户执行删除(无权限)
System.out.println("===== 普通用户 =====");
DataManager target = new DataManager();
ProxyFactory proxyFactory1 = new ProxyFactory();
proxyFactory1.setTarget(target);
proxyFactory1.setProxyTargetClass(true);
proxyFactory1.addAdvice(new PermissionAdvice("USER"));
DataManager proxy1 = (DataManager) proxyFactory1.getProxy();
proxy1.queryData(); // 普通操作允许
try {
proxy1.deleteData(); // 敏感操作拒绝
} catch (SecurityException e) {
System.out.println(e.getMessage());
}
// 测试2:管理员执行删除(有权限)
System.out.println("\n===== 管理员 =====");
ProxyFactory proxyFactory2 = new ProxyFactory();
proxyFactory2.setTarget(target);
proxyFactory2.setProxyTargetClass(true);
proxyFactory2.addAdvice(new PermissionAdvice("ADMIN"));
DataManager proxy2 = (DataManager) proxyFactory2.getProxy();
proxy2.deleteData();
}
}
执行结果:
===== 普通用户 =====
[权限校验] USER 用户执行 queryData 操作,校验通过
执行数据查询
[权限校验] USER 用户执行 deleteData 操作,校验通过
权限不足:仅管理员可执行删除操作
===== 管理员 =====
[权限校验] ADMIN 用户执行 deleteData 操作,校验通过
执行数据删除
场景 4:缓存管理
核心需求 :对高频查询的方法结果进行缓存,避免重复计算 / 查询数据库,提升性能。实现方式:通过动态代理在方法执行前检查缓存,有缓存则直接返回,无缓存则执行方法并将结果存入缓存。
场景 5:远程调用(如 RPC 框架)
核心需求 :本地调用接口方法时,动态发起网络请求调用远程服务(如 Dubbo、Feign)。实现方式 :动态代理生成接口的代理类,代理类的 invoke 方法中封装网络请求逻辑,调用远程服务并返回结果。
场景 6:异常统一处理
核心需求 :对多个方法的异常进行统一捕获和处理(如转换异常类型、记录异常日志、返回兜底结果)。实现方式:通过动态代理捕获目标方法的异常,执行统一的异常处理逻辑。
三、Spring 框架中动态代理的典型应用
除了上述业务场景,Spring 自身也大量使用动态代理:
- Spring AOP :所有
@Aspect切面的实现(如@Before、@After、@Around); - Spring 声明式事务 :
@Transactional注解的底层实现; - Spring Security:权限校验、认证逻辑的增强;
- Spring Cache :
@Cacheable、@CacheEvict等缓存注解; - Spring Cloud Feign:声明式 HTTP 客户端的远程调用;
- MyBatis:Mapper 接口的代理(虽然不是 Spring 代理,但原理一致)。
四、总结
核心要点回顾
- 使用时机:需要无侵入增强方法、统一处理通用逻辑、解耦横切逻辑与业务逻辑时,优先用动态代理;
- 核心场景:日志监控、事务管理、权限校验、缓存管理、远程调用、异常统一处理;
- Spring 落地 :Spring 动态代理是 AOP 的核心,
ProxyFactory是创建代理的核心工厂,可灵活选择 JDK/CGLIB 代理,通过Advice/Interceptor实现方法增强。
动态代理的核心价值是「开闭原则」------ 对扩展开放(新增增强逻辑),对修改关闭(不修改目标类源码),这也是它成为框架核心机制的根本原因。