java动态代理

动态代理

动态代理是一种在运行时创建代理对象的技术,它能够在不修改目标对象源代码的情况下,对目标对象的方法调用进行增强或控制。以下从几个方面详细介绍动态代理:

1. 基本概念
  • 代理对象:动态代理会创建一个代理对象,这个代理对象会代替目标对象接收外部的方法调用。它看起来和目标对象具有相同的接口,外部调用者可以像调用目标对象一样调用代理对象的方法。

  • 目标对象:也就是被代理的实际对象,它包含了真正要执行的业务逻辑。代理对象最终会将接收到的方法调用转发给目标对象去执行。

2. 工作原理
  • 当外部调用者调用代理对象的某一方法时,代理对象首先会拦截这个方法调用。然后,它可以根据具体需求进行一些前置处理,比如进行权限验证、日志记录等操作。

  • 完成前置处理后,代理对象会将方法调用转发给目标对象,让目标对象执行真正的业务逻辑。

  • 在目标对象执行完业务逻辑返回结果后,代理对象还可以进行一些后置处理,比如对返回结果进行加工、统计方法执行时间等操作,最后再将处理后的结果返回给外部调用者。

3. 实现方式(以 Java 为例)

Java 中有两种常见的实现动态代理的方式:基于接口的动态代理(使用 Java 反射机制和java.lang.reflect.Proxy类)和基于类的动态代理(使用第三方库如 CGLIB)。

基于接口的动态代理

  • 要求目标对象必须实现一个或多个接口。

  • 示例代码如下:

复制代码
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 ​
 // 定义接口
 interface HelloWorld {
     void sayHello();
 }
 ​
 // 实现接口的目标对象
 class HelloWorldImpl implements HelloWorld {
     @Override
     public void sayHello() {
         System.out.println("Hello, World!");
     }
 }
 ​
 // 实现InvocationHandler接口,用于处理代理对象的方法调用
 class MyInvocationHandler implements InvocationHandler {
     private final Object target;
 ​
     public MyInvocationHandler(Object target) {
         this.target = target;
     }
 ​
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         // 前置处理,比如记录日志
         System.out.println("Before method call: " + method.getName());
 ​
         // 调用目标对象的方法并获取结果
         Object result = method.invoke(target, args);
 ​
         // 后置处理,比如统计方法执行时间
         System.out.println("After method call: " + method.getName());
 ​
         return result;
     }
 }
 ​
 public class DynamicProxyExample {
     public static void main(String[] args) {
         // 创建目标对象
         HelloWorld helloWorld = new HelloWorldImpl();
 ​
         // 创建InvocationHandler对象
         MyInvocationHandler handler = new MyInvocationHandler(helloWorld);
 ​
         // 创建代理对象
         HelloWorld proxy = (HelloWorld) Proxy.createProxyInstance(HelloWorld.class.getClassLoader(),
                 new Class[]{HelloWorld.class}, handler);
 ​
         // 调用代理对象的方法
         proxy.sayHello();
     }
 }

在上述代码中:

  • 首先定义了HelloWorld接口和实现该接口的HelloWorldImpl目标对象。

  • 然后创建了MyInvocationHandler类,它实现了InvocationHandler接口,用于处理代理对象的方法调用。在invoke方法中实现了前置处理、调用目标对象方法以及后置处理的功能。

  • 最后通过Proxy.createProxyInstance方法创建了代理对象,并调用代理对象的方法,此时可以看到前置处理和后置处理的效果。

基于类的动态代理(以 CGLIB 为例)

  • 不需要目标对象实现接口,它可以直接代理类。

  • 示例代码如下:

复制代码
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;
 import net.sf.cglib.proxy.MethodProxy;
 ​
 // 目标对象,没有实现任何接口
 class HelloWorld {
     public void sayHello() {
         System.out.println("Hello, World!");
     }
 }
 ​
 // 实现MethodInterceptor接口,用于处理代理对象的方法调用
 class MyMethodInterceptor implements MethodInterceptor {
     @Override
         public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
             // 前置处理,比如记录日志
             System.out.println("Before method call: " + method.getName());
 ​
             // 调用目标对象的方法并获取结果
             Object result = proxy.invokeSuper(obj, args);
 ​
             // 后置处理,比如统计方法执行时间
             System.out.println("After method call: " + method.getName());
 ​
             return result;
         }
 }
 ​
 public class CglibDynamicProxyExample {
     public static void main(String[] args) {
         // 创建目标对象
         HelloWorld helloWorld = new HelloWorld();
 ​
         // 创建Enhancer对象
         Enhancer enhancer = new Enhancer();
 ​
         // 设置目标对象的类
         enhancer.setTarget(helloWorld);
 ​
         // 设置MethodInterceptor
         enhancer.setCallback(new MyMethodInterceptor());
 ​
         // 创建代理对象
         HelloWorld proxy = (HelloWorld) enhancer.create();
 ​
         // 调用代理对象的方法
         proxy.sayHello();
     }
 }

在上述代码中:

  • 定义了没有实现任何接口的HelloWorld目标对象。

  • 然后创建了MyMethodInterceptor类,它实现了MethodInterceptor接口,用于处理代理对象的方法调用。在intercept方法中实现了前置处理、调用目标对象方法以及后置处理的功能。

  • 最后通过Enhancer创建了代理对象,并调用代理对象的方法,同样可以看到前置处理和后置处理的效果。

4. 应用场景
  • 权限控制:在企业级应用中,对于不同用户访问某些敏感业务方法时,可以通过动态代理在方法调用前进行权限验证,只有具备相应权限的用户才能访问到真正的业务方法。

  • 日志记录:为了方便跟踪和分析应用程序的运行情况,可以在代理对象的方法调用前后分别进行日志记录,记录下方法的名称、参数、执行时间等信息,以便于后续的故障排查和性能分析。

  • 性能监控:通过动态代理可以统计目标对象的方法执行时间,以此来评估业务方法的执行效率,及时发现可能存在的性能问题并进行优化。

动态代理是一种非常有用的技术,它为软件开发提供了一种灵活的方式来对目标对象的方法调用进行增强和控制,在许多应用场景中都发挥着重要作用。

相关推荐
paopaokaka_luck7 分钟前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
以后不吃煲仔饭20 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师20 分钟前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
The_Ticker26 分钟前
CFD平台如何接入实时行情源
java·大数据·数据库·人工智能·算法·区块链·软件工程
大数据编程之光1 小时前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
ExiFengs1 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
paj1234567891 小时前
JDK1.8新增特性
java·开发语言
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
慧都小妮子1 小时前
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
java·pdf·.net