Java案例中的动态代理怎么用?

wen java案例 4

Java动态代理使用指南

动态代理是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类和方法

最佳实践建议

  1. 优先使用JDK动态代理,除非需要代理没有接口的类
  2. Spring Framework中默认使用JDK动态代理,如果目标类没有实现接口则使用CGLIB
  3. 注意性能:频繁创建代理对象可能影响性能,考虑缓存代理对象
  4. 代理链:可以组合多个InvocationHandler实现复杂代理逻辑

希望这些示例能帮助你理解Java动态代理的使用!

抱歉,评论功能暂时关闭!