Java动态代理使用指南
动态代理是Java中非常强大的特性,允许在运行时动态创建代理类并拦截方法调用,主要有两种实现方式:

JDK动态代理(基于接口)
JDK动态代理要求目标对象必须实现接口。
示例:用户管理系统的日志代理
// 1. 定义业务接口
public interface UserService {
void addUser(String username);
void deleteUser(int id);
String getUserInfo(int id);
}
// 2. 实现类(目标对象)
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户: " + username);
}
@Override
public void deleteUser(int id) {
System.out.println("删除用户ID: " + id);
}
@Override
public String getUserInfo(int id) {
return "用户信息: ID=" + id;
}
}
// 3. 实现InvocationHandler(代理逻辑)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogInvocationHandler implements InvocationHandler {
private Object target; // 目标对象
public LogInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:记录日志
System.out.println("[日志] 调用方法: " + method.getName() +
", 参数: " + java.util.Arrays.toString(args));
// 调用目标方法
Object result = method.invoke(target, args);
// 后置增强:记录结果
System.out.println("[日志] 方法执行完成,返回值: " + result);
return result;
}
}
// 4. 客户端使用
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 创建InvocationHandler
LogInvocationHandler handler = new LogInvocationHandler(userService);
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(), // 类加载器
userService.getClass().getInterfaces(), // 接口列表
handler // 调用处理器
);
// 通过代理对象调用方法
proxy.addUser("张三");
System.out.println("---");
proxy.deleteUser(1001);
System.out.println("---");
String info = proxy.getUserInfo(2002);
System.out.println(info);
}
}
CGLIB动态代理(基于继承)
CGLIB可以代理没有实现接口的类。
// 导入CGLIB包(需要额外引入cglib依赖)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 1. 目标类(无需实现接口)
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
// 2. 实现MethodInterceptor
public class LogMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("[日志] 执行方法: " + method.getName() +
", 参数: " + Arrays.toString(args));
// 调用父类方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("[日志] 方法返回: " + result);
return result;
}
}
// 3. 使用CGLIB创建代理
public class CglibProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 设置父类(目标类)
enhancer.setSuperclass(Calculator.class);
// 设置回调方法拦截器
enhancer.setCallback(new LogMethodInterceptor());
// 创建代理对象
Calculator proxy = (Calculator) enhancer.create();
// 通过代理调用方法
System.out.println("结果: " + proxy.add(10, 20));
System.out.println("---");
System.out.println("结果: " + proxy.subtract(50, 30));
}
}
实际应用场景
场景1:事务管理
public class TransactionInvocationHandler implements InvocationHandler {
private Object target;
private TransactionManager transactionManager;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// 开启事务
transactionManager.beginTransaction();
// 调用业务方法
Object result = method.invoke(target, args);
// 提交事务
transactionManager.commit();
return result;
} catch (Exception e) {
// 回滚事务
transactionManager.rollback();
throw e;
}
}
}
场景2:权限控制
public class SecurityInvocationHandler implements InvocationHandler {
private Object target;
private User currentUser;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查是否需要权限
if (method.isAnnotationPresent(RequirePermission.class)) {
RequirePermission permission = method.getAnnotation(RequirePermission.class);
if (!currentUser.hasPermission(permission.value())) {
throw new SecurityException("权限不足");
}
}
return method.invoke(target, args);
}
}
优缺点对比
JDK动态代理:
- ✅ 优点:Java原生支持,无需额外依赖
- ❌ 缺点:只能代理实现了接口的类
CGLIB动态代理:
- ✅ 优点:可以代理普通类
- ❌ 缺点:需要额外引入cglib依赖,不能代理final类和方法
最佳实践建议
- 优先使用JDK动态代理,除非需要代理没有接口的类
- Spring Framework中默认使用JDK动态代理,如果目标类没有实现接口则使用CGLIB
- 注意性能:频繁创建代理对象可能影响性能,考虑缓存代理对象
- 代理链:可以组合多个InvocationHandler实现复杂代理逻辑
希望这些示例能帮助你理解Java动态代理的使用!