欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 金融 > Java 之动态代理详解

Java 之动态代理详解

2025/3/12 22:08:26 来源:https://blog.csdn.net/weixin_64178283/article/details/142463606  浏览:    关键词:Java 之动态代理详解

动态代理就像是一位神奇的魔术师,它能悄无声息地在你的代码运行时,为你的对象添加各种功能,而这一切,你不需要修改任何已有的代码!

一、什么是代理?

想象一下,你想要出国旅游,但你不会外语,也不熟悉当地的风俗习惯。这时候,你就可以找一家旅行社,让他们帮你安排行程、预订酒店、办理签证等等。对你来说,旅行社就相当于你的代理,你只需要告诉他们你的需求,他们就会帮你完成所有的事情。

在软件开发中,代理也是类似的概念。代理对象就像中间人一样,它会拦截对目标对象的访问,并在访问前后执行一些额外的操作,比如记录日志、权限校验、缓存等等。

二、动态代理的魔力:运行时创建

代理模式有很多种实现方式,而动态代理则是其中最灵活的一种。它最大的特点就是在程序运行时,动态地创建代理对象和代理类,而不需要我们手动编写代理类的代码。

那么,Java是如何实现动态代理的呢?答案就是——反射!(点击查看什么是反射)

三、Java动态代理三剑客

Java提供了以下三种方式来实现动态代理:

  1. JDK动态代理: 基于接口的动态代理,使用 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

  2. CGLIB动态代理: 基于继承的动态代理,使用第三方库CGLIB。

  3. ASM动态代理: 基于字节码操作的动态代理,使用第三方库ASM。

本文将重点介绍使用最广泛的JDK动态代理,其他两种方式留待后续文章中探讨。

四、JDK动态代理实战:打造万能日志记录器

假设我们有一个 UserService 接口和一个 UserServiceImpl 实现类,现在我们想在调用 UserServiceImpl 的每个方法前后都打印一条日志,记录方法的执行时间。

1. 定义接口和实现类:

// UserService 接口
public interface UserService {void createUser(String username, String password);void deleteUser(String username);
}// UserServiceImpl 实现类
public class UserServiceImpl implements UserService {@Overridepublic void createUser(String username, String password) {System.out.println("创建用户:" + username);// 模拟业务逻辑执行try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic void deleteUser(String username) {System.out.println("删除用户:" + username);// 模拟业务逻辑执行try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}
}

2. 创建 InvocationHandler 实现类:

// InvocationHandler 实现类,用于处理代理逻辑
public class LogInvocationHandler implements InvocationHandler {// 目标对象private Object target;public LogInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 方法执行前的逻辑long startTime = System.currentTimeMillis();System.out.println("开始执行方法:" + method.getName());// 调用目标对象的方法Object result = method.invoke(target, args);// 方法执行后的逻辑long endTime = System.currentTimeMillis();System.out.println("方法执行结束:" + method.getName() + ",耗时:" + (endTime - startTime) + "ms");return result;}
}

3. 创建代理对象:

public class Main {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);                            // InvocationHandler 对象// 调用代理对象的方法proxy.createUser("zhangsan", "123456");proxy.deleteUser("lisi");}
}

代码解释:

  • LogInvocationHandler 实现了 InvocationHandler 接口,并在 invoke() 方法中定义了代理逻辑,即在目标方法执行前后打印日志。

  • Proxy.newProxyInstance() 方法用于创建代理对象。它需要三个参数:

    • 类加载器: 用于加载代理类。

    • 接口数组: 目标对象实现的接口数组,代理类会实现这些接口。

    • InvocationHandler 对象: 用于处理代理逻辑。

  • 调用代理对象的方法时,实际上会调用 LogInvocationHandler 的 invoke() 方法,从而实现记录日志的功能。

运行结果:

开始执行方法:createUser
创建用户:zhangsan
方法执行结束:createUser,耗时:104ms
开始执行方法:deleteUser
删除用户:lisi
方法执行结束:deleteUser,耗时:103ms

4.invoke() 方法

在Java中,invoke方法主要用于反射机制,它属于java.lang.reflect.Method类。通过这个方法,可以动态地调用某个类的实例方法或静态方法。

invoke方法的基本用法

public Object invoke(Object obj, Object... args) throws IllegalAccessException, InvocationTargetException;
  • 参数
    • obj:调用方法的对象实例。如果是静态方法,可以传null
    • args:调用方法时需要的参数,可以是可变参数数组。

使用示例

下面是一个简单的例子,演示如何使用invoke方法:

import java.lang.reflect.Method;class Example {public void sayHello(String name) {System.out.println("Hello, " + name + "!");}
}public class Main {public static void main(String[] args) {try {// 创建 Example 类的实例Example example = new Example();// 获取 sayHello 方法Method method = Example.class.getMethod("sayHello", String.class);// 调用 sayHello 方法method.invoke(example, "World");} catch (Exception e) {e.printStackTrace();}}
}

注意事项

  1. 权限问题:如果方法是私有的,使用反射调用时需要设置为可访问。
  2. 异常处理invoke方法可能会抛出多个异常,如IllegalAccessExceptionInvocationTargetException,需要适当处理。
  3. 性能开销:反射会比直接调用方法慢,因此在性能敏感的场合需谨慎使用。

五、总结

动态代理是Java中一个非常强大的机制,它可以帮助我们实现很多灵活的功能,比如:

  • AOP(面向切面编程)

  • RPC(远程过程调用)

  • 事务管理

  • 缓存等等

希望通过本文的介绍,你已经对Java动态代理有了初步的了解。在实际开发中,我们可以根据具体的需求,灵活运用动态代理,让我们的代码更加优雅高效!感谢各位看官的观看,下期见,谢谢~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词