java动态代理怎么写

接口,创建代理类实现 InvocationHandler 接口,用 Proxy.newProxyInstance() 生成

是关于Java动态代理的详细实现指南:

java动态代理怎么写

核心原理与组件

Java动态代理基于JDK内置的java.lang.reflect.Proxy类和InvocationHandler接口实现,其本质是在运行时动态生成一个代理类的字节码,该类会实现目标对象的接口,并将所有方法调用转发给指定的调用处理器(即InvocationHandler),这种机制允许开发者在不修改原始类的情况下,为对象添加额外的行为逻辑(如日志记录、性能监控等)。

组件 作用 关键方法/结构
InvocationHandler 定义如何处理方法调用,包含实际的业务逻辑或横切关注点(例如前置/后置操作) invoke(Object proxy, Method method, Object[] args)
Proxy 根据接口信息创建动态代理实例 getProxyClass(ClassLoader loader, Class<?>[] interfaces) + newInstance()

实现步骤详解

定义业务接口

首先需要有一个或多个被代理的目标接口,我们创建一个用户服务的接口:

public interface UserService {
    void addUser(String name);
    void deleteUser(int id);
}

注意:JDK动态代理要求目标必须是接口类型,不能直接代理具体类(若需代理类,则应使用CGLIB)。

实现InvocationHandler

编写自定义的调用处理器,在其中编码增强逻辑,以下示例展示了如何添加日志功能:

java动态代理怎么写

import java.lang.reflect.Method;
import java.util.Arrays;
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("[LOG] Calling method: " + method.getName() + " with args: " + Arrays.toString(args));
        // 执行原始方法
        Object result = method.invoke(target, args);
        // 后置通知:打印返回结果
        System.out.println("[LOG] Method returned: " + result);
        return result;
    }
}

此处的method.invoke(target, args)会真正调用目标对象的方法,而上下两部分则是插入的公共逻辑。

创建代理对象

通过Proxy.newProxyInstance()工厂方法生成代理实例:

// 假设已有一个实现了UserService的具体类 RealUserService
UserService realImpl = new RealUserService();
// 包装成InvocationHandler
LoggingHandler handler = new LoggingHandler(realImpl);
// 获取代理对象(强制转换为对应接口类型)
UserService proxyInstance = (UserService) Proxy.newProxyInstance(
    realImpl.getClass().getClassLoader(),          // 使用与目标相同的类加载器
    new Class[]{UserService.class},                 // 要代理的接口列表
    handler                                       // 自定义的调用处理器
);

此时proxyInstance就是一个完全功能的代理对象,它可以像普通对象一样调用方法,但内部会自动触发日志记录。

验证效果

测试代码如下:

java动态代理怎么写

public class Main {
    public static void main(String[] args) {
        UserService userService = (UserService) Proxy.newProxyInstance(...); // 同上一步
        userService.addUser("Alice");              // 输出日志并执行添加操作
        userService.deleteUser(1001);              // 输出日志并执行删除操作
    }
}

运行后控制台将显示类似以下内容:

[LOG] Calling method: addUser with args: [Alice]
[LOG] Method returned: null
[LOG] Calling method: deleteUser with args: [1001]
[LOG] Method returned: null

典型应用场景

  • AOP面向切面编程:统一处理事务提交回滚、权限校验等跨模块需求;
  • 性能监控:统计各个接口的响应时间;
  • 缓存机制:对高频查询的结果进行临时存储;
  • 远程过程调用(RPC):作为服务端存根自动打包传输协议。

优缺点分析

优势 局限性
✅ 无需修改原有代码 ❌ 仅支持基于接口的代理(不支持类的代理)
✅ 运行时动态生成代理类 ❌ 性能略低于直接调用(因反射机制开销)
✅ 灵活扩展公共逻辑 ❌ 无法拦截final方法或构造函数
✅ 松耦合设计 ❌ 复杂嵌套调用可能导致栈溢出风险

FAQs

Q1: 如果目标类没有实现任何接口,还能用JDK动态代理吗?
A: 不能,JDK动态代理要求目标必须实现至少一个接口,如果需要代理普通类,应改用CGLIB库(基于字节码增强技术),它可以直接代理非接口类,例如使用Enhancer类配合MethodInterceptor实现类似功能。

Q2: 为什么有时会出现“java.lang.IllegalArgumentException: No such method definition”错误?
A: 此异常通常由两个原因导致:①传递给Proxy.newProxyInstance()的接口列表与目标对象实际实现的接口不一致;②调用的方法不存在于声明的接口中,解决方案是仔细检查接口定义和方法签名是否匹配,若接口声明了void save();但实现类写成了int save(),就会因返回

原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/110712.html

(0)
酷盾叔的头像酷盾叔
上一篇 2025年8月20日 05:55
下一篇 2025年8月20日 06:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN