Java 的动态代理

Java 的动态代理(Dynamic Proxy)是 Java 提供的一种允许在运行时动态创建代理对象的机制,用于拦截和处理对目标对象方法的调用,它基于 Java 的反射机制,被广泛运用于 AOP (面向切面编程)、框架开发(如 Spring)等领域。

区别于静态代理(需要手动编写代理类),动态代理在运行时通过反射动态生成代理类,无需为每个目标类手动编写代理代码。

Java 中的动态代理主要基于 java.lang.reflect.Proxy 和 InvocationHandler 接口。其中 Proxy 类用于动态生成代理对象,InvocationHandler 接口用于定义代理逻辑,每次调用代理对象的方法时,会触发 InvocationHandler 的 invoke 方法。

动态代理要求目标对象必须实现至少一个接口,因为代理对象是通过接口生成的。

下面给出一个简单的动态代理示例:

java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义一个接口
interface UserService {
    void sayHello(String name);
}

// 目标类(被代理的实现类)
class UserServiceImpl implements UserService {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name + "!");
    }
}

// 自定义 InvocationHandler
class MyInvocationHandler implements InvocationHandler {
    private Object target; // 目标对象

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前:记录日志");
        Object result = method.invoke(target, args); // 调用目标对象的方法
        System.out.println("方法调用后:清理资源");
        return result;
    }
}

// 测试
public class Main {
    public static void main(String[] args) {
        // 创建目标对象
        UserServiceImpl target = new UserServiceImpl();

        // 创建 InvocationHandler
        MyInvocationHandler handler = new MyInvocationHandler(target);

        // 生成代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(), // 类加载器
            target.getClass().getInterfaces(),  // 目标实现的接口
            handler                             // InvocationHandler
        );

        // 调用代理对象的方法
        proxy.sayHello("Alice");
    }
}

输出结果:

java 复制代码
方法调用前:记录日志
Hello, Alice!
方法调用后:清理资源

Prxoy.newProxyInstance 在运行时生成一个代理类,这个代理类的字节码是动态创建的,通常以 $Proxy0 这样的形式命名,代理类的每个方法都会调用 InvocationHandler.invoke 。

当调用代理对象的方法(如 proxy.sayHello)时,实际执行的是 InvocationHandler.invoke。invoke 方法接收三个参数:proxy 表示代理对象本身,method 表示被调用的方法(反射的 Method 对象),args 表示方法参数。在 invoke 中可以自定义逻辑(如日志、权限检查),然后通过 method.invoke(target, args) 调用目标对象的方法。

动态代理实现了代理逻辑与业务逻辑分离,符合 AOP 思想。同一个 InvocationHandler 可以代理多个接口或对象。

动态代理使用的反射机制有一定的性能开销。

相关推荐
C雨后彩虹2 分钟前
CAS与其他并发方案的对比及面试常见问题
java·面试·cas·同步·异步·
java1234_小锋1 小时前
Java高频面试题:SpringBoot为什么要禁止循环依赖?
java·开发语言·面试
2501_944525541 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter
计算机学姐1 小时前
基于SpringBoot的电影点评交流平台【协同过滤推荐算法+数据可视化统计】
java·vue.js·spring boot·spring·信息可视化·echarts·推荐算法
Filotimo_2 小时前
Tomcat的概念
java·tomcat
索荣荣2 小时前
Java Session 全面指南:原理、应用与实践(含 Spring Boot 实战)
java·spring boot·后端
Amumu121382 小时前
Vue Router(二)
java·前端
念越3 小时前
数据结构:栈堆
java·开发语言·数据结构
千寻技术帮3 小时前
10333_基于SpringBoot的家电进存销系统
java·spring boot·后端·源码·项目·家电进存销