Java中的动态代理机制详解
字数 958 2025-11-03 20:46:32
Java中的动态代理机制详解
一、动态代理的概念与作用
动态代理是一种在运行时动态创建代理类和对象的技术,它允许你在不修改原始类代码的情况下,为对象的方法调用添加额外功能(如日志记录、权限检查、事务管理等)。动态代理的核心价值在于实现"横切关注点"的分离。
二、动态代理的实现方式
Java提供了两种主要的动态代理实现方式:
-
JDK动态代理
- 基于接口实现,要求目标类必须实现至少一个接口
- 核心类:
java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler
-
CGLIB动态代理
- 基于继承实现,通过生成目标类的子类来创建代理
- 可以代理没有实现接口的普通类
三、JDK动态代理的详细实现步骤
步骤1:定义业务接口
// 用户服务接口
public interface UserService {
void addUser(String username);
void deleteUser(String username);
}
步骤2:实现业务接口(目标类)
// 目标类 - 实际业务逻辑的实现
public 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接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LoggingHandler implements InvocationHandler {
private final Object target; // 目标对象
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:方法执行前的逻辑
System.out.println("【日志】开始执行方法: " + method.getName());
System.out.println("【日志】参数: " + (args != null ? String.join(",", args) : "无"));
long startTime = System.currentTimeMillis();
// 调用目标对象的原始方法
Object result = method.invoke(target, args);
// 后置增强:方法执行后的逻辑
long endTime = System.currentTimeMillis();
System.out.println("【日志】方法执行耗时: " + (endTime - startTime) + "ms");
System.out.println("【日志】方法执行完成");
return result;
}
}
步骤4:创建代理对象并使用
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建InvocationHandler实例
InvocationHandler handler = new LoggingHandler(target);
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 类加载器
target.getClass().getInterfaces(), // 接口数组
handler // 调用处理器
);
// 通过代理对象调用方法
proxy.addUser("张三");
proxy.deleteUser("李四");
}
}
四、CGLIB动态代理的实现
步骤1:添加CGLIB依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
步骤2:实现MethodInterceptor接口
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibLoggingInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("【CGLIB日志】开始执行方法: " + method.getName());
long startTime = System.currentTimeMillis();
// 调用父类(目标类)的方法
Object result = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("【CGLIB日志】方法执行耗时: " + (endTime - startTime) + "ms");
return result;
}
}
步骤3:创建代理对象
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(UserServiceImpl.class);
// 设置回调处理器
enhancer.setCallback(new CglibLoggingInterceptor());
// 创建代理对象
UserService proxy = (UserService) enhancer.create();
proxy.addUser("王五");
}
}
五、两种动态代理的对比分析
| 特性 | JDK动态代理 | CGLIB动态代理 |
|---|---|---|
| 实现基础 | 基于接口 | 基于继承 |
| 性能 | 调用反射方法,较慢 | 直接调用父类方法,较快 |
| 限制 | 必须实现接口 | 不能代理final类和方法 |
| 依赖 | JDK原生支持 | 需要额外jar包 |
六、动态代理的实际应用场景
- Spring AOP:Spring框架使用动态代理实现面向切面编程
- MyBatis:Mapper接口的代理实现
- Hibernate:延迟加载功能的实现
- RPC框架:远程方法调用的客户端代理
- 事务管理:声明式事务的实现基础
七、核心原理深入理解
动态代理的核心在于:
- 代理类生成:在运行时通过字节码技术动态生成代理类的字节码
- 方法转发:所有方法调用都被重定向到InvocationHandler的invoke方法
- 责任链模式:通过代理链实现多个增强功能的组合
通过动态代理,我们可以实现业务逻辑与横切关注点的彻底分离,大大提高代码的可维护性和复用性。