当前位置: 首页 > news >正文

java的动态代理

Java 中的动态代理是一种设计模式,允许程序在运行时动态地生成代理类,而不是在编译时确定。它的主要作用是对接口的实现进行增强,使得我们可以在调用方法前后添加一些操作,比如日志、事务控制等。动态代理有两种常见的实现方式:

  1. JDK 动态代理:基于接口实现的代理,使用 java.lang.reflect.ProxyInvocationHandler
  2. CGLIB 动态代理:基于子类继承的代理,使用字节码生成,适用于没有接口的类。

以下是对这两种实现方式的原理和示例的详细介绍。


1. JDK 动态代理

JDK 动态代理基于 Java 的 Proxy 类和 InvocationHandler 接口来实现,只能代理实现了接口的类。其原理是通过生成代理类在调用方法时拦截,并由 InvocationHandler 中的 invoke() 方法处理。

实现原理
  • 代理类生成:在运行时,Proxy 类使用 Proxy.newProxyInstance() 方法生成代理对象。
  • 方法拦截:代理对象调用方法时会被 InvocationHandler 接口的 invoke() 方法拦截,invoke() 方法可以在调用前后插入逻辑。
  • 字节码生成:JDK 动态代理利用字节码生成技术动态生成代理类,在 JVM 中加载执行。
实现示例

假设我们有一个 Service 接口和它的实现类 ServiceImpl

public interface Service {void performTask();
}public class ServiceImpl implements Service {public void performTask() {System.out.println("Executing task...");}
}

创建动态代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DynamicProxyHandler implements InvocationHandler {private final Object target;public DynamicProxyHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Before method invocation");Object result = method.invoke(target, args);System.out.println("After method invocation");return result;}public static void main(String[] args) {// 创建目标对象Service target = new ServiceImpl();// 创建代理对象Service proxy = (Service) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new DynamicProxyHandler(target));// 调用代理方法proxy.performTask();}
}

执行结果

Before method invocation
Executing task...
After method invocation
适用场景
  • 适用于代理接口类,不能代理普通类。
  • 常用于拦截器、权限控制、日志记录、事务管理等。

2. CGLIB 动态代理

CGLIB(Code Generation Library)是一种基于字节码生成的动态代理实现方式,能够代理普通类,适用于没有实现接口的类。CGLIB 动态代理通过生成目标类的子类,并重写其中的方法来实现。

实现原理
  • 子类继承:CGLIB 通过生成目标类的子类实现代理,目标类的方法被拦截。
  • 方法拦截:代理类调用方法时会被 MethodInterceptor 拦截,MethodInterceptor 可以在方法调用前后加入自定义逻辑。
  • 字节码增强:CGLIB 通过 ASM 字节码生成框架动态生成字节码,并在 JVM 中加载。
实现示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class CGLibProxy implements MethodInterceptor {private final Object target;public CGLibProxy(Object target) {this.target = target;}public Object createProxy() {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method invocation");Object result = proxy.invokeSuper(obj, args);System.out.println("After method invocation");return result;}public static void main(String[] args) {// 目标对象ServiceImpl target = new ServiceImpl();// 创建代理对象ServiceImpl proxy = (ServiceImpl) new CGLibProxy(target).createProxy();// 调用代理方法proxy.performTask();}
}

执行结果

Before method invocation
Executing task...
After method invocation
适用场景
  • 适用于没有接口的普通类。
  • 由于 CGLIB 是通过继承实现的,所以无法代理 final 方法和 final 类。

JDK 动态代理和 CGLIB 的对比

特性JDK 动态代理CGLIB 动态代理
代理方式基于接口基于继承
性能较高,适合频繁调用的小方法较低,但适合复杂的调用
代理目标接口普通类(但不能代理 final 类和方法)
实现库Java 自带第三方库(cglibspring-core
常用场景AOP、拦截器等代理没有接口的类,AOP

总结

动态代理是一种重要的设计模式,允许在运行时动态增强对象的功能。JDK 动态代理适合代理接口,CGLIB 则适合没有接口的类。通过了解两者的原理和实现,可以灵活运用动态代理技术来增强 Java 应用的功能,如日志、事务管理、权限控制等。


http://www.mrgr.cn/news/65236.html

相关文章:

  • 使用 `Celery` 配合 `RabbitMQ` 作为消息代理,实现异步任务的调度、重试、定时任务以及错误监控等功能
  • VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
  • 如何封装一个axios,封装axios有哪些好处
  • 【十九周】文献阅读:图像识别的深度残差学习
  • 1、Qt6 Quick 简介
  • 红黑树代码详解
  • OTFS基带通信系统(脉冲导频,信道估计,MP解调算法)
  • Linux 常用命令整理大全及命令使用心得
  • 薄膜与胶带展同期论坛:新质生产力下的薄膜与胶带工艺与材料之美
  • 风险分析方法-敏感性分析
  • leetcode刷题记录(二十)——383. 赎金信
  • 管家婆财贸ERP BB090.销售单指定客户控制超期应收款
  • 2024年计算机视觉与图像处理国际学术会议 (CVIP 2024)
  • PYNQ 框架 - VDMA驱动 - 帧缓存
  • 算法竞赛(Python)-大事化小,小事化了(分治)
  • vscode php Launch built-in server and debug, PHP内置服务xdebug调试,自定义启动参数配置使用示例
  • LoRA(Low-Rank Adaptation)的工作机制 - 低秩矩阵来微调全连接层
  • JAVA学习-练习试用Java实现“判断奇偶数”
  • NFC碰一碰支付系统私有化部署的实用技巧!
  • 中国逐年最大NDVI数据集(250m)
  • 软件项目管理 之 6抓6放
  • 【JavaEE】【网络原理】初识网络
  • 重新构想定性数据分析:使用 NVivo 15 实现 AI、反思和备忘录
  • 彻底理解cookie、session、token
  • 近十年视觉任务中的对抗攻击研究综述
  • 解锁数字人直播:重塑行业生态,让真人出镜成过去式?