动态代理是 Java 中非常核心的设计模式(代理模式的进阶),简单说就是在程序运行时动态生成代理类,而非编译期提前写死,能灵活地为目标对象的方法增加额外逻辑(如日志、权限、事务),且无需修改目标类代码,是 Spring AOP 等框架的底层核心。


一、核心概念(通俗理解)
  • 目标对象:真正执行业务逻辑的对象(比如 UserService)。
  • 代理对象:动态生成的 “包装类”,负责调用目标对象方法,并在调用前后加额外逻辑。
  • 核心接口 / 类
    • InvocationHandler:代理逻辑的核心接口,需实现 invoke() 方法(这里写额外逻辑)。
    • Proxy:JDK 提供的工具类,通过 newProxyInstance() 动态生成代理对象。

注意:JDK 动态代理只能代理实现了接口的类;如果要代理无接口的类,需用 CGLIB(基于继承)。

二、极简实战代码(JDK 动态代理)

以 “给用户服务的方法加日志” 为例,完整可运行代码:

java

运行

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 1. 定义业务接口(JDK动态代理必须有接口)
interface UserService {
    void addUser(String username);
    void deleteUser(String username);
}

// 2. 实现目标类(真正的业务逻辑)
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,编写代理逻辑
class LogInvocationHandler implements InvocationHandler {
    // 目标对象(被代理的对象)
    private final Object target;

    // 构造方法传入目标对象
    public LogInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 代理核心方法:每次调用代理对象的方法,都会执行这里
     * @param proxy 代理对象本身(一般不用)
     * @param method 被调用的方法(如addUser)
     * @param args 方法参数(如username)
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置增强:调用目标方法前加日志
        System.out.println("[日志] 执行方法:" + method.getName() + ",参数:" + (args != null ? args[0] : "无"));
        
        // 调用目标对象的真实方法
        Object result = method.invoke(target, args);
        
        // 后置增强:调用目标方法后加日志
        System.out.println("[日志] 方法" + method.getName() + "执行完成");
        
        return result;
    }
}

// 4. 测试动态代理
public class DynamicProxyDemo {
    public static void main(String[] args) {
        // 1. 创建目标对象
        UserService target = new UserServiceImpl();
        
        // 2. 创建代理处理器
        InvocationHandler handler = new LogInvocationHandler(target);
        
        // 3. 动态生成代理对象(核心方法)
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  // 类加载器
                target.getClass().getInterfaces(),   // 目标对象实现的接口
                handler                              // 代理逻辑处理器
        );
        
        // 4. 调用代理对象的方法(会触发invoke())
        proxy.addUser("张三");
        proxy.deleteUser("李四");
    }
}
三、代码运行结果

plaintext

[日志] 执行方法:addUser,参数:张三
新增用户:张三
[日志] 方法addUser执行完成
[日志] 执行方法:deleteUser,参数:李四
删除用户:李四
[日志] 方法deleteUser执行完成
四、核心关键点解释
  1. Proxy.newProxyInstance()
    • 三个参数:类加载器(和目标对象一致)、目标对象的接口数组、InvocationHandler 实现类。
    • 返回值是实现了目标接口的代理对象,可直接强转为目标接口类型。
  2. invoke () 方法
    • 所有代理对象的方法调用都会转发到这里。
    • method.invoke(target, args) 是真正调用目标对象的方法,缺一不可。
  3. 应用场景
    • Spring AOP(面向切面编程):核心就是动态代理,实现日志、事务、权限的统一管理。
    • RPC 框架(如 Dubbo):代理远程服务接口,隐藏网络通信细节。
五、JDK 动态代理 vs CGLIB(补充)

表格

特性 JDK 动态代理 CGLIB 代理
底层实现 实现目标接口 继承目标类
适用场景 有接口的类 无接口的类
性能 JDK8+ 后性能优于 CGLIB 早期版本性能好,现在略逊
限制 不能代理类(只能代理接口) 不能代理 final 类 / 方法

总结

  1. Java 动态代理的核心是运行时生成代理类,核心类是 Proxy(生成代理)和 InvocationHandler(代理逻辑)。
  2. JDK 动态代理仅支持接口代理,无接口场景需用 CGLIB,Spring 默认自动切换两者。
  3. 动态代理是 AOP、RPC 等技术的底层基础,核心价值是无侵入式增强方法逻辑
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐