Java静态代理和动态代理

通过一个小案例整理描述静态代理和动态代理

给大家举个简单例子。在一个公司中,老板处于上层,客户在下层。因每天来访客户众多,老板本应只考虑战略和赚钱,却被一些不重要的客户耽误不少时间。于是老板招聘了一个秘书,专门负责接待客户和登记客户来访。这就如同我们的代码,业务类只需负责核心业务代码,非业务代码如请求用时记录、事务开启、健全及异常处理等,交给代理去做,从而降低代码耦合度,将业务代码和公共代码分离,提高可维护性。这个例子属于静态代理,因为招来的秘书只负责客户来访登记。但还有很多事务需要安排,随着公司发展,王总、张总等也需要秘书,此时秘书类会增多,还需临时去找秘书。所以静态代理有局限性,在编译期就确定了要做的事情,无法代理全部方法,每个不同类型的目标类都需要一个代理类。

如何解决这种困境呢?通过动态代理可以解决。我们将人力公司视为动态代理,它可以动态派遣秘书,根据需求动态获取秘书。主流的人力公司有 JDK 和 CGLIB。它们的区别在于 JDK 需要提前签署协议,即 JDK 动态代理需要目标类实现接口,因为它生成的 class 是通过实现目标类的接口;而 CGLIB 则没有任何限制,因为生成的 class 是通过继承目标类。

那么 JDK 动态代理和 CGLIB 哪个更快呢?由于 JDK 动态代理底层是通过反射调用,没有 “合同” 得临时找,而 CGLIB 是实时调用,可以立马把 “合同” 派遣过来。听起来好像 JDK 动态代理更慢,但由于 JDK1.8 之后对反射进行了性能优化,所以在调用过程中性能不会有差别。

因此,我们可以根据目标类是否实现了接口,选择不同的动态代理技术。如果我们使用了 Spring AOP 的话,它的底层会根据我们使用的目标类,动态选择不同的动态代理技术。


一、静态代理

静态代理是由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class 文件就已经存在了。

实现方式
- 定义一个接口,被代理对象和代理对象都实现这个接口。
- 代理对象持有被代理对象的引用,并在实现接口方法时,可以在调用被代理对象的方法前后添加额外的逻辑。
优点
- 结构简单直观,容易理解和实现。
- 可以在不修改被代理对象的情况下,为其添加额外的功能。
缺点
- 如果接口有很多方法,代理类需要实现所有方法,代码冗余。
- 当需要代理多个不同的对象时,需要为每个对象都创建一个代理类,不够灵活。

下面图为动态代理示例图

二、动态代理(JDK 动态代理)

JDK 动态代理是基于 Java 反射机制实现的。它要求被代理的对象必须实现一个接口。

实现方式
- 通过实现`InvocationHandler`接口创建一个调用处理器对象。
- 使用`Proxy.newProxyInstance()`方法创建代理对象。这个方法接收三个参数:类加载器、被代理对象实现的接口数组和调用处理器对象。
- 当调用代理对象的方法时,实际上会调用调用处理器的`invoke()`方法,在这个方法中可以添加额外的逻辑,并通过反射调用被代理对象的方法。
优点
- 代理对象的生成是在程序运行时动态完成的,更加灵活。
- 可以减少代码冗余,因为不需要为每个被代理对象都编写一个代理类。
缺点
- 只能代理实现了接口的对象。
三、CGLIB 动态代理

CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库。它可以在运行时动态生成被代理对象的子类来实现代理功能。

实现方式
- 实现`MethodInterceptor`接口创建一个方法拦截器对象。
- 使用`Enhancer`类设置被代理对象的类、方法拦截器等信息,然后调用`create()`方法创建代理对象。
- 当调用代理对象的方法时,会调用方法拦截器的`intercept()`方法,在这个方法中可以添加额外的逻辑,并通过反射调用被代理对象的方法。
优点
- 可以代理没有实现接口的类。
- 性能较高,生成的代理类是被代理对象的子类,直接调用方法,不需要通过反射。
缺点
- 不能代理 final 类和 final 方法。
四、Spring Boot 中的代理方式

Spring Boot 主要使用了 JDK 动态代理和 CGLIB 动态代理。

  1. 当被代理的对象实现了一个或多个接口时,Spring 默认使用 JDK 动态代理。例如,当使用 Spring 的事务管理注解@Transactional时,如果被注解的对象实现了接口,Spring 会使用 JDK 动态代理来创建事务代理对象。
  2. 如果被代理的对象没有实现接口,Spring 会使用 CGLIB 来生成代理对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1534523.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

大模型进行Query改写时如何提升性能

Query改写方法有子问题拆解、短语提取、回溯检索、虚拟文档等方法。见:https://blog.csdn.net/qq_43814415/article/details/138606669 llama-index的实现见:https://zhaozhiming.github.io/2024/05/13/query-rewrite-rag/ 这里总结实际使用大模型改写时…

Day09-StatefuleSet控制器

Day09-StatefuleSet控制器 0、昨日内容回顾1、StatefulSets控制器1.1 StatefulSet概述1.2 StatefulSets控制器-网络唯一标识之headless1.3 StatefulSets控制器-独享存储 2、metric-server2.1 metric-server概述2.2 部署metric-server:2.3 hpa案例 3、helm概述3.1 安装helm3.2 h…

并行程序设计基础——并行I/O(5)

目录 一、分布式数组文件的存取 1.1 MPI_TYPE_CREATE_DARRAY 1.2 MPI_TYPE_CREATE_SUBARRAY 二、小结 上一节我们对并行I/O中共享文件的存取操作进行了介绍,本节继续介绍MPI-2并行I/O的最后内容:分布式数组文件的存取。 一、分布式数组文件的存取 许多情况下,M…

ModbusTCP/RTU转Ethernet/IP(CIP)-Modbus设备与罗克韦尔AB的PLC之间通讯

IGT-DSER智能网关模块支持西门子、三菱、欧姆龙、罗克韦尔AB等各种品牌的PLC之间通讯,同时也支持PLC与Modbus协议的工业机器人、智能仪表、变频器等设备通讯。网关有多个网口、串口,也可选择WIFI无线通讯。无需PLC内编程开发,只要在IGT-DSER智…

两段有趣的代码(C语言函数指针)

目录 part1part2 两段有趣的代码 part1 (*(void (*)())0)();我们知道函数指针: void (*p)()去掉函数指针变量名就是函数指针的类型: void (*)()那这段代码我们就可以理解为将0强制转换为函数指针类型,再进行解引用;进行调用函数&#xff…

【视频教程】基于PyTorch深度学习无人机遥感影像目标检测、地物分类及语义分割实践技术应用

随着无人机自动化能力的逐步升级,它被广泛的应用于多种领域,如航拍、农业、植保、灾难评估、救援、测绘、电力巡检等。但同时由于无人机飞行高度低、获取目标类型多、以及环境复杂等因素使得对无人机获取的数据处理越来越复杂。最近借助深度学习方法&…

解锁企业潜能,Vatee万腾平台引领智能新纪元

在数字化转型的浪潮中,企业正站在一个前所未有的十字路口,面对着前所未有的机遇与挑战。解锁企业内在潜能,实现跨越式发展,已成为众多企业的共同追求。而Vatee万腾平台,作为智能科技的先锋,正以其强大的智能…

JavaSE篇之内部类和图书系统

1.内部类(类中类) 在Java中,将一个类定义在另一个类内部,前者称为内部类,后者称为外部类。 注意事项: 1. 1.静态内部类(被static修饰的内部类) 1.在静态内部类的方法中不能直接引用外部类的成员变量&…

为什么自动驾驶技术的实现离不开4G+5G多卡聚合?

如今,汽车制造商和零部件巨头都在研究自动驾驶相关技术。要实现汽车的自动驾驶,不乏相关技术与道路环境的结合和变化。但要实现这一目标,最重要的环节无疑是建设网络。 在4G时代,随着网络带宽和速度的提高,可以实现实…

Skydel如何使用USRP完成GNSS信号仿真?

作者介绍 一、Skydel与NI USRP 软件定义架构(Software Defined Architecture)是一种新型的架构模式,它是一种基于软件的架构,通过软件来定义系统的功能,从而提高系统的运行效率和能量效率。软件定义架构可以将硬件…

玩机搞机-----如何简单的使用ADB指令来卸载和冻结系统应用 无需root权限 详细操作图示教程

同类博文: 玩机搞机---卸载内置软件 无root权限卸载不需要的软件 安全卸载_无需root卸载彻底内置软件-CSDN博客 在很多时候我们需要卸载一些系统级的app。但如果直接手机端进行卸载的话。是无法正常卸载的。其实我们可以通过有些成品工具或者完全靠ADB指令来进行卸…

一种简单的过某宝验证码的方式(仅做学习使用)

开篇 今天介绍一种简单的过某宝验证码的方式,用的是自动化,这样对不会js逆向的小白非常友好,只需要用到selenium框架就能轻松过某宝验证码,即模拟人的操作对滑块进行滑动。 但是首先还是需要训练验证码和标题 训练前&#xff1a…

Apisix离线安装

上传离线包 #ll apisix-3.2.2-0.el7.x86_64.rpm apisix-base-1.21.4.1.8-0.el7.x86_64.rpm apisix-dashboard-3.0.1-0.el7.x86_64.rpm cyrus-sasl-2.1.26-24.el7_9.x86_64.rpm cyrus-sasl-devel-2.1.26-24.el7_9.x86_64.rpm cyrus-sasl-gssapi-2.1.26-24.el7_9.x86_64.rpm cyr…

K8s利用etcd定时备份集群结合钉钉机器人通知

如何通过脚本的方式进行K8s集群的备份 查看K8s中master节点中etcd集群的状态 kubectl get pods -n kube-system | grep etcd由于使用的etcd服务是K8s搭建时自身携带的,并不是独立搭建的etcd集群信息。使用 K8s 搭建集群时,etcd 是 Kubernetes 集成的一个重要组件因此需要查…

多线程面试题-28问

1、查询Java有哪些线程? public class MultiThread {public static void main(String[] args) {// 获取 Java 线程管理 MXBeanThreadMXBean threadMXBean ManagementFactory.getThreadMXBean();// 不需要获取同步的 monitor 和 synchronizer 信息,仅获…

朗迪锋亮相2024年中国国际服务贸易交易会

9月12日至14日,2024中国国际服务贸易交易会(以下简称“服贸会”)在国家会议中心和首钢园区成功举办。本届服贸会由商务部和北京市人民政府共同主办,继续秉承“全球服务 互惠共享”的宗旨,与参展企业一同聚焦“共享智慧…

开源项目低代码表单FormCreate中通过接口加载远程数据选项

在开源项目低代码表单 FormCreate 中,fetch 属性提供了强大的功能,允许从远程 API 加载数据并将其应用到表单组件中。通过灵活的配置,fetch 可以在多种场景下发挥作用,从简单的选项加载到复杂的动态数据处理。 源码地址: Github …

再次进阶 舞台王者 第八季完美童模全球赛代言人【刘诗乐】赛场秀场超燃合集!

7月20-23日,2024第八季完美童模全球总决赛在青岛圆满落幕。在盛大的颁奖典礼上,一位才能出众的少女——刘诗乐迎来了她舞台生涯的璀璨时刻。 代言人——刘诗乐,以璀璨童星之姿,优雅地踏上完美童模盛宴的绚丽舞台,作为开…

WebGL系列教程八(GLSL着色器基础语法)

目录 1 前言2 基本原则3 基本数据类型4 顶点着色器和片元着色器4.1 声明4.2 初始化项目4.3 赋值 5 结构体5.1 声明5.2 赋值 6 函数6.1 基本结构6.2 自定义函数6.3 常用内置函数 7 精度8 其他9 总结 1 前言 通过前七讲,我们已经见过了WebGL中的部分基础语法&#xff…

性能诊断的方法(三):异常信息诊断方法

关于性能诊断的方法,我们可以按照“问题现象—直接原因—问题根源”这样一个思路去归纳。我们先从问题的现象去入手,包括时间的分析、资源的分析和异常信息的分析。接下来再去分析产生问题现象的直接原因是什么,这里我们归纳了自上而下的资源…