Spring学习笔记—JDK动态代理

在这里插入图片描述

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉
🍎个人主页:Leo的博客
💞当前专栏: Spring专栏
✨特色专栏: MySQL学习
🥭本文内容:Spring学习笔记—JDK动态代理
🖥️个人小站 :个人博客,欢迎大家访问
📚个人知识库: 知识库,欢迎大家访问

  • 学习参考 :

    • 讲师:孙帅老师
    • 课程:孙哥说Spring5

1.前言

前面文章我们学习了关于Spring的IOC与AOP相关知识点,在此之前,我们主要学习Spring的一些核心概念,IOCAOP等等。我们之前学习了简单了解了AOP如何借助动态字节码技术来构建动态代理类。实现动态代理的方式不止一种。本次系列文章主要介绍两种:JDK动态代理CGlib动态代理,主要主要介绍JDK动态代理。首先,我们将着重了解JDK动态代理的核心原理和实际应用情境。好了,话不多说,让我们开始吧😎😎😎。

2.什么是JDK动态代理

大家都知道,AOP底层是动态代理,而Java中的动态代理有两种实现方式:

  • 基于 JDK 的动态代理
  • 基于 Cglib 的动态代理

这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口,而基于 Cglib 的动态代理并不需要被代理对象有接口。

那么大家不禁要问,Spring 中的 AOP 是怎么实现的?是基于 JDK 的动态代理还是基于 Cglib 的动态代理?那我们就先来里了解一下JDK动态代理

在Spring框架中,JDK动态代理是一种实现代理模式的技术,用于在运行时动态地生成代理对象。它是基于Java的反射机制实现的。

JDK动态代理主要涉及两个核心接口:InvocationHandlerProxy

  1. InvocationHandler接口: InvocationHandler是一个接口,它定义了一个方法invoke(Object proxy, Method method, Object[] args)。在使用JDK动态代理时,我们需要实现InvocationHandler接口,并在该方法中编写代理逻辑。

    invoke方法中,代理对象的方法调用会被重定向到invoke方法中进行处理。我们可以在invoke方法中添加额外的逻辑,如在方法调用前后做一些处理、拦截方法调用、修改方法参数等。通过invoke方法,我们可以在不修改原始对象的情况下,对其方法进行增强或增加额外的行为。

  2. Proxy类: Proxy类是JDK提供的一个工具类,用于创建代理对象。它提供了一个静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),用于创建代理对象。

    newProxyInstance方法接受三个参数:

    • ClassLoader loader:指定代理对象的类加载器。
    • Class<?>[] interfaces:指定代理对象要实现的接口。
    • InvocationHandler h:指定实现了InvocationHandler接口的对象,用于处理方法调用。

    newProxyInstance方法会返回一个实现了指定接口的代理对象,该代理对象会将方法调用转发给指定的InvocationHandler对象。

我们可以通过这张流程图来清楚的了解JDK动态代理的执行流程:

image-20231025215100690

3.JDK动态代理的优缺点

3.1优点

JDK动态代理有以下优点:

  1. 简单易用: 使用JDK动态代理可以快速创建代理对象,无需手动编写代理类,减少了代码的编写量和维护成本。
  2. 高效性能: JDK动态代理是通过Java的反射机制实现的,底层通过字节码生成和动态类加载的方式来创建代理对象。相比于其他代理方式,JDK动态代理的性能较高。
  3. 纯Java实现: JDK动态代理是Java标准库的一部分,不依赖第三方库或框架,能够直接在Java应用中使用。
  4. 松耦合: JDK动态代理可以对接口进行代理,代理对象与目标对象之间通过接口进行交互,实现了目标对象和代理对象的解耦。
  5. 面向接口: JDK动态代理主要面向接口,可以为接口中的所有方法提供代理,对于实现了多个接口的对象,可以为每个接口提供不同的代理逻辑。

3.2缺点

JDK动态代理也有一些缺点:

  1. 只能代理接口: JDK动态代理只能代理实现了接口的目标对象,对于没有实现接口的类无法进行代理。这限制了JDK动态代理的使用范围。
  2. 无法直接访问目标对象的私有方法: JDK动态代理只能代理目标对象的公共方法,无法直接访问目标对象的私有方法。如果需要对私有方法进行代理,需要通过其他方式实现。
  3. 创建代理对象的性能开销:在创建代理对象时,JDK动态代理需要通过反射和动态类加载来生成代理类,这会带来一定的性能开销。但一旦代理对象创建完成后,后续的方法调用性能与普通方法调用相当。

4.JDK动态代理的开发步骤

使用JDK动态代理时,我们需要遵循以下步骤:

  1. 创建一个实现了InvocationHandler接口的代理处理器类,实现其中的invoke方法,编写代理逻辑。
  2. 使用Proxy类的newProxyInstance方法创建代理对象,传入类加载器、接口数组和代理处理器对象。
  3. 使用代理对象调用方法时,方法调用会被重定向到代理处理器的invoke方法中。在invoke方法中,可以进行额外的处理或增强。

JDK动态代理在Spring框架中被广泛应用,例如在AOP(面向切面编程)中,用于实现切面逻辑和方法拦截。通过JDK动态代理,可以实现对目标对象的方法调用进行拦截、增强、事务管理等操作,提供了一种灵活而有弹性的代理方式。

4.1ClassLoader

ClassLoader,即类加载器,在Java中起着至关重要的作用。但要深入了解它,首先必须回顾Java程序的标准运行流程。典型情况下,当程序启动时,类加载器首先会读取类对应的字节码文件(.class文件),将其加载到JVM中。随后,JVM会基于这些字节码数据,通过类加载器创建出对应的Class对象,并根据需要进一步实例化为具体对象。

这个流程在遇到动态代理时遭遇了挑战。动态代理,顾名思义,其类是在运行时动态生成的,它并没有预先准备好的.class文件。那么,如何为这样的代理类创建一个Class对象呢?又或者说,ClassLoader在这里扮演什么角色?

实际上,当我们请求JVM创建一个动态代理时,JVM会为我们临时生成这个代理类的字节码。这并不是从文件系统中读取的,而是基于我们给定的接口和实现,即时生成的。 在这里,ClassLoader的任务是加载这个临时生成的字节码到JVM的内存中。这意味着,尽管代理类的字节码并没有物理存在,但ClassLoader依然可以处理它,就像处理其他常规Java类一样。

但这里有一个细节值得注意:这个用于加载动态代理的ClassLoader并不是新创建的,而是借用了现有的一个类加载器。这点尤为重要,因为在Java项目中,每个类都有它自己对应的类加载器,确保了类的隔离和安全性。在动态代理的场景中,我们实际上是复用了某个现有类的加载器来加载代理类,确保代理类能够顺利地与原始 类在同一个上下文中工作

4.2Class<?>[]

在**Proxy.newProxyInstance()**方法中,第二个参数Class<?>[]起着至关重要的作用。它是一个Class对象的数组,代表了一组接口。当我们希望创建一个动态代理对象时,这些接口定义了创建的代理对象将额外功能加在哪些原始类方法上。

为什么是接口而不是具体的类呢?这是因为JDK的动态代理机制建立在接口的基础之上。具体来说,动态代理生成的代理类会实现指定的一组接口,而不是继承某个类。这使得动态代理具有很大的灵活性,因为一个Java类可以实现多个接口,但只能继承一个父类。

通过传递一个Class对象的数组作为参数,我们告诉JVM我们希望代理类实现哪些接口,将额外功能加在哪些原始类方法上。然后,动态生成的代理类将会实现这些接口,并在每个接口方法的实现中,根据我们的需求,调用InvocationHandler来处理方法调用。

简而言之,Class<?>[]参数为**Proxy.newProxyInstance()**方法提供了一个蓝图,说明代理类应如何构建,并且定义了其行为特征

4.3InvocationHandler

InvocationHandler是JDK动态代理机制中的一个关键接口,其定义了如何在代理对象上处理方法调用。该接口中,仅包含一个名为invoke的方法。此方法在设计上,旨在调用原始对象的方法,同时为其注入额外的功能。

当代理对象上的一个方法被调用时,invoke方法就会被触发。它提供了我们一个场所,允许我们在原始方法执行前后添加自定义的行为或功能,从而扩展或改变原始方法的行为。
关于invoke方法的三个参数,它们分别为:

Proxy:这是正在调用的方法所属的代理实例。大多数情况下,我们并不直接使用它,因为在InvocationHandler实现内部调用该代理对象会导致无限递归。
Method:这代表了被代理对象的某个具体方法的反射对象它为我们提供了调用原始对象方法的能力,这可以通过method.invoke(targetObject, args)来完成,其中targetObject是原始对象的实例。
Object[]:这是被代理方法的参数数组,表示在代理对象上调用方法时传递的参数。
通过组合上述三个参数,我们可以在invoke方法中灵活地调用原始方法,同时根据需要为其添加额外的逻辑或功能,从而实现对原始方法行为的定制。

在我们深入了解JDK的InvocationHandler接口后,不禁让人回想起Spring AOP中的一个相似结构——MethodInterceptor接口。Spring AOP在动态代理实现中提供了这个接口,它与JDK的动态代理机制的核心思想相似,但是Spring对其进行了封装。

MethodInterceptor接口的设计是简洁而聚焦的。它的中心是一个invoke方法,这个方法的目的与InvocationHandler中的invoke相似: 拦截并增强方法调用。但不同的是,Spring选择了一个集成的方法来传递信息。而不是分开的多个参数,MethodInterceptor的invoke方法接受一个封装了方法调用详情的MethodInvocation对象。这个对象包含了调用的方法、目标对象、参数等所有必要的信息,而且还提供了一个proceed方法,用于执行原始的方法调用。

image-20231025215429544

5.JDK动态代理小结

总的来说,JDK动态代理是一种简单易用、高效性能、纯Java实现的代理技术,适用于面向接口的场景。它具有松耦合的特点,能够将代理对象与目标对象解耦,但同时也存在一些局限性,如只能代理接口、无法直接访问私有方法等。根据具体的使用场景和需求,选择合适的代理方式才能发挥代理的优势。

6.参考文献

  • https://www.itheima.com/news/20210525/165219.html
  • https://blog.csdn.net/luoyoub/article/details/80101376
  • https://spring.io/
  • https://blog.csdn.net/qq_43266723/article/details/133488696

7.总结

以上便是本文的全部内容,本人才疏学浅,文章有什么错误的地方,欢迎大佬们批评指正!我是Leo,一个在互联网行业的小白,立志成为更好的自己。

如果你想了解更多关于Leo,可以关注公众号-程序员Leo,后面文章会首先同步至公众号。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis -- 基础知识2

1.Redis客户端介绍 1.基础介绍 Redis是一种客户端-服务器结构的程序&#xff0c;通过网络进行互动 客户端的多种形态 1.自带了命令行客户端&#xff1a;redis-cil 2.图形化界面的客户端&#xff1a;依赖windows系统&#xff0c;连接服务器有诸多限制&#xff0c;不建议使用 3.基…

打印机连接网络后怎么安装驱动?

打印机在我们办公和生活中算是比较常见的设备&#xff0c;特别是在上班时需要时常打印各种文件&#xff0c;但是有时电脑上的打印机也会有无法打印的问题&#xff0c;或者新买的打印机需要先安装驱动才能正常打印的。 那么这个时候我们需要先检查电脑上的打印机是否有安装驱动&…

正点原子嵌入式linux驱动开发——异步通知

上一篇笔记中使用阻塞或者非阻塞的方式来读取驱动中按键值都是应用程序主动读取的&#xff0c;对于非阻塞方式来说还需要应用程序通过poll函数不断的轮询。最好的方式就是驱动程序能主动向应用程序发出通知&#xff0c;报告自己可以访问&#xff0c;然后应用程序再从驱动程序中…

LCR 146. 螺旋遍历二维数组

LCR 146. 螺旋遍历二维数组 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; LCR 146. 螺旋遍历二维数组 https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/description/ 完成情况&#xff1a; 解…

【Leetcode】【每日一题】【简单】2520. 统计能整除数字的位数

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/count-the-digits-that-divide-a…

网络安全保险行业面临的挑战与变革

保险业内大多数资产类别的数据可以追溯到几个世纪以前&#xff1b;然而&#xff0c;网络安全保险业仍处于初级阶段。由于勒索软件攻击、高度复杂的黑客和昂贵的数据泄漏事件不断增加&#xff0c;许多网络安全保险提供商开始感到害怕继续承保更多业务。 保险行业 根据最近的路…

【方法】如何给PDF文件添加“打开密码”?

PDF文件可以在线浏览&#xff0c;但如果想要给文件添加“打开密码”&#xff0c;就需要用到软件工具&#xff0c;下面小编分享两种常用的工具&#xff0c;小伙伴们可以根据需要选择。 工具一&#xff1a;PDF编辑器 PDF阅读器一般是没有设置密码的功能模块&#xff0c;PDF编辑器…

python自动化测试(二):xpath获取元素

目录 前置代码 一、什么是xpath方式 二、通过xpath 单组属性名属性值 的方式进行元素定位 三、通过xpath的多组属性进行元素的定位 四、通过xpath文本值的方式进行元素定位 五、通过模糊的文本值方式进行元素定位 前置代码 # codingutf-8 from selenium import webdrive…

python树结构包treelib入门及其计算应用

树是计算机科学中重要的数据结构。例如决策树等机器学习算法设计、文件系统索引等。创建treelib包是为了在Python中提供树数据结构的有效实现。 Treelib的主要特点包括&#xff1a; 节点搜索的高效操作。支持常见的树操作&#xff0c;如遍历、插入、删除、节点移动、浅/深复制…

使用Go语言测试Redis性能

1. 前言 Redis是一个高性能的键值存储数据库&#xff0c;常用于缓存、队列、排行榜等场景。在实际应用中&#xff0c;我们需要对Redis的性能进行测试&#xff0c;以便了解其在不同场景下的表现。本文将介绍如何使用Go语言测试Redis的性能。 2. 环境准备 在开始测试前&#x…

如何让家居设备快速通过Matter认证?移远通信为您带来标准回答

2022年10月&#xff0c;Matter协议正式面向全球发布&#xff1b;2023年10月23日&#xff0c;Matter 1.2最新版本正式发布。在Matter发布至今的时日里&#xff0c;众多头部厂商纷纷加速开发新产品&#xff0c;只为更快抢占市场先机&#xff0c;以“先发者”身份入局新赛道&#…

数据库安全定义以及重要性简单讲解

数据库安全定义 数据库安全指的是对数据库进行保护&#xff0c;以确保其数据的机密性、完整性和可用性&#xff0c;并防止非法访问、篡改、破坏、泄露等安全威胁。一般包括访问控制、数据加密、审计和监控、数据备份、漏洞修补、网络安全等方面。 数据库安全的重要性 1、数据…

C++ 学习 之 名字空间 namespace

必须在模块里面 extern 声明 在一个 cpp 文件中&#xff0c; 一个namespace 可以多次定义&#xff0c;最后合并&#xff0c;使用 using namespace A 这种引入方式的话&#xff0c;使用的时候可以用所有 A 中的数据 多个 cpp 文件的话&#xff0c;不能会自动合并相同的 名字空…

HackTheBox - Starting Point -- Tier 0 ---Preignition

文章目录 一 题目二 实验过程 一 题目 Tags Web、Custom Applications、Apache、Reconnaissance、Web Site Structure Discovery、Default Credentials译文&#xff1a;Web、定制应用程序、Apache、侦察、网站结构发现、默认凭证Connect To attack the target machine, you …

论文-分布式-分布式计算|容错-分布式控制下的自稳定系统

参考文献Self-stabilizing systems in spite of distributed control可以把松散耦合的 循环序列过程 间的同步任务&#xff0c;看成是要保持一个这样的不变性&#xff1a;“系统要处于一种合法状态”因此每个进程在运行每一个可能会改变不变性的步骤之前都要先检查一下是可以执…

人机环境系统智能是东方与西方智能思想的融合

人机环境系统的思想是一种综合性的思想&#xff0c;它融合了东方思想和西方思想的元素。在东方文化中&#xff0c;人类与自然环境有着密切的联系&#xff0c;强调人类与自然环境的和谐共生关系。而在西方文化中&#xff0c;科技和机器的应用越来越广泛&#xff0c;对人类社会和…

21.2 Python 使用Scapy实现端口探测

Scapy 是一款使用纯Python编写的跨平台网络数据包操控工具&#xff0c;它能够处理和嗅探各种网络数据包。能够很容易的创建&#xff0c;发送&#xff0c;捕获&#xff0c;分析和操作网络数据包&#xff0c;包括TCP&#xff0c;UDP&#xff0c;ICMP等协议&#xff0c;此外它还提…

十四天学会C++之第八天:文件操作

1. 文件的打开和关闭 文件操作的基本概念。打开文件&#xff1a;使用fstream库打开文件以供读写。关闭文件&#xff1a;确保文件在使用完毕后正确关闭。 文件的打开和关闭&#xff1a;C 文件操作入门 在C编程中&#xff0c;文件操作是一项重要的任务&#xff0c;可以读取和写…

《Cesium 进阶知识点》- el-select 列表打开后,点击Cesium.Viewer场景无法自动关闭

前提 el-select属性 popper-append-to-body 必须 为 false。这样初始化的列表 el-select-dropdown 才在 el-select下&#xff1b;目前测试&#xff0c;仅对 Cesium.Viewer 生成的 canvas 点击时列表无法自动关闭&#xff1b;使用原生 canvas 和 echarts&#xff0c;点击其场景…

vivado简单仿真入门

打开软件 创建工程 create project ![在这里插入图片描述](https://img-blog.csdnimg.cn/892eda626d394733920854b71ca8f726.png)先next,保留工程路径&#xff0c;配置环境 配置芯片环境 本次芯片类型 xc7k325tffg900-2 创建之后完整的demo 编写仿真内容 timescale 1ns/1…