Spring学习笔记—JDK动态代理

news2024/9/28 3:18:48

在这里插入图片描述

✅作者简介:大家好,我是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.coloradmin.cn/o/1133230.html

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

相关文章

Unity中Shader的ShaderLOD

文章目录 前言一、ShaderLOD的使用步骤1、ShaderLOD使用在不同的SubShader中&#xff0c;用于区分SubShader所对应的配置2、在 C# 中使用 Shader.globalMaximumLOD 赋值来选择不同的 SubShader,以达到修改配置对应Shader的效果3、在设置LOD时&#xff0c;是需要和程序讨论统一 …

WebGL笔记:矩阵的变换之平移的实现

矩阵的变换 变换 变换有三种状态&#xff1a;平移、旋转、缩放。当我们变换一个图形时&#xff0c;实际上就是在移动这个图形的所有顶点。解释 webgl 要绘图的话&#xff0c;它是先定顶点的&#xff0c;就比如说我要画个三角形&#xff0c;那它会先把这三角形的三个顶点定出来…

为什么需要山洪灾害监测预警系统?

在山洪高发地区&#xff0c;安装山洪灾害监测预警系统能够通过实时监测&#xff0c;预警山洪信息&#xff0c;对于保障我们的生命财产安全具有重要意义。 监测山洪不仅需要对山体进行监测&#xff0c;还要监测降雨量以及水位上升情况。山洪灾害监测预警系统是由GNSS监测站和水…

linux安装node(含npm命令) 并配置淘宝镜像源

1. 下载压缩包 wget https://nodejs.org/dist/v16.14.0/node-v16.14.0-linux-x64.tar.xz # node14 https://nodejs.org/dist/v14.15.4/node-v14.15.4-linux-x64.tar.xz # 推荐将压缩包放置到/usr/local/node文件夹中安装 mv node-v16.14.0-linux-x64.tar.xz /usr/local/node …

LeetCode217——存在重复元素

LeetCode217——存在重复元素 1.题目描述&#xff1a; 给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 &#xff0c;返回 true &#xff1b;如果数组中每个元素互不相同&#xff0c;返回 false 。 2.Result01(暴力解) public static boolean containsDuplicate(in…

SRAM与DRAM的区别

目录 SRAM 特点 应用场景 DRAM 特点 应用场景 SRAM和DRAM的区别 SRAM SRAM&#xff08;静态随机存取存储器&#xff09;是一种用于存储和检索数据的类型的计算机内存。SRAM的存储单元通过触发器&#xff08;flip-flop&#xff09;实现&#xff0c;它们可以保持数据的状态…

语雀崩溃7个小时的原因是什么??

1 语雀是什么 语雀是蚂蚁集团旗下的在线文档编辑与协同工具&#xff0c;使用了“结构化知识库管理”&#xff0c;形式上类似书籍的目录。用户量在千万级别&#xff0c;是非常强大的。身边有不少朋友是付费会员&#xff0c;有许多公司也付费在使用语雀作为知识库进行文档的存储…

通过社工进网站后台的渗透测试

目录 通过社工进网站后台 0X0 开始&#xff1a; 0X1 获取icp备案企业&#xff1a; 0X2 通过备案获取姓名&#xff1a; 0X3 通过姓名获取手机号&#xff1a; 0X4 弱口令进后台&#xff1a; 0X5 总结 通过社工进网站后台 记录一次通过简单社工获取信息后进入后台的经过。…

近似熵的计算

我们计算两个函数,一个是henon,另外一个是TriMap: 代码: 构造henon函数: function [x,y]=Henon(x0,y0,a,b,M) M=M+10000; x = zeros(1,M+1); y = zeros(1,M+1); x(1)=x0; y(1)=y0; for i = 1:Mx(i+1) = 1+y(i)-a*x(i)^2;y(i+1) = b*x(i); endx=x(10001:M); y=y(10001:M)…

【人工智能Ⅰ】实验1:谓词表示法与产生式知识表示

实验1 谓词表示法与产生式知识表示 一、实验目的 1、熟悉谓词逻辑表示法&#xff1b; 2、理解和掌握产生式知识表示方法&#xff0c;实现产生式系统的规则库。 二、实验内容 要求通过C/C/python语言编程实现&#xff1a; 1、猴子摘香蕉问题 2、动物识别系统 &#xff08…

C# 基于腾讯云人脸核身和百度云证件识别技术相结合的 API 实现

目录 腾讯云人脸核身技术 Craneoffice.net 采用的识别方式 1、活体人脸核身(权威库)&#xff1a; 2、活体人脸比对&#xff1a; 3、照片人脸核身(权威库)&#xff1a; 调用成本 百度云身份证识别 调用成本 相关结合点 核心代码 实现调用人脸核身API的示例 实现调用身…

css 三栏布局的实现?

目录 前言 用法 代码 理解 高质量图片 1. 左侧栏 - 导航菜单 2. 中间栏 - 主要内容 3. 右侧栏 - 小部件和广告 布局的响应式设计 三栏布局在前端页面设计中是一个常见的布局方式&#xff0c;通常包含左侧、中间和右侧三个部分。这种布局方式在多种场景中都很受欢迎&am…

企业安全—DevSecOps概述详情

0x00 前言 SDL存在的问题在于体量过于庞大&#xff0c;不利于快速进行适配和进行&#xff0c;所以就有了DevSecOps&#xff0c;实际上是因为敏捷开发也就是DevOps的推进&#xff0c;并且坐上了云服务模式的火车&#xff0c;所以这一系列的东西都开始普及。DevSecOps作为DevOps…

龙迅LT9211 是MIPI/TTL/2 PORT LVDS互转的一颗高性能芯片,支持车规级

龙迅LT9211 描述&#xff1a; Lontium LT9211是一个高性能转换器&#xff0c;可以在MIPI DSI/CSI-2/双端口LVDS和TTL之间互转换&#xff0c;除了24位TTL到24位TTL与同步和DE。LT9211反序列化输入的MIPI/LVDS/TTL视频数据&#xff0c;解码数据包&#xff0c;并将格式化的视频数…

2006-2021年上市公司社会责任报告基本信息数据

2006-2021年上市公司社会责任报告基本信息表数据 1、时间&#xff1a;2006-2021年 2、来源为上市公司社会责任BG 3、指标&#xff1a;股票代码、统计截止日期、GG日期、所属省份、行业代码、行业名称、纳税总额、每股社会贡献值、社会捐赠额、是否经第三方机构审验、审验机构…

Python Opencv实践 - 入门使用Tesseract识别图片中的文字

做车牌识别项目前试一试tesseract识别中文。tesseract的安装使用请参考&#xff1a; Python OCR工具pytesseract详解 - 知乎pytesseract是基于Python的OCR工具&#xff0c; 底层使用的是Google的Tesseract-OCR 引擎&#xff0c;支持识别图片中的文字&#xff0c;支持jpeg, png…

Android 中如何使用 App Links

1. 简介 什么是 App Links呢&#xff1f;App Links 是 Android 6.0 (API 级别23) 引入的新功能&#xff0c;它是基于 DeepLinking&#xff0c;允许应用自动处理网站的 URL&#xff0c;而无需提示用户启动相应的应用。 例如&#xff1a;如果你在手机浏览器中输入了某个网站&am…

小红书女性用户洞察|2023「她研究」深度数据报告

作为新时代女性群体的聚集地、发声场&#xff0c;小红书不断涌现的「她」话题&#xff0c;承载着不同的女性特质&#xff0c;对理想自我、理想生活的期待&#xff0c;以及消费行为与决策偏好。 当代女性为回答「我是谁」、「我要什么」、「我想成为什么样的自己」&#xff0c;倾…

YOLOv7改进:全网原创首发 | 新颖的多尺度卷积注意力(MSCA),即插即用,助力小目标检测 | NeurIPS2022

💡💡💡本文全网首发独家改进:多尺度卷积注意力(MSCA),有效地提取上下文信息,新颖度高,创新十足。 1)作为注意力MSCA使用; 推荐指数:五星 MSCA | 亲测在多个数据集能够实现涨点,多尺度特性在小目标检测表现也十分出色。 收录: YOLOv7高阶自研专栏介绍:…

【网安大模型专题10.19】论文4:大模型+自动生成代码评估:改进自动化测试方法、创建测试输入生成器、探索新的评估数据集扩充方法,提高编程基准的精度

Is Your Code Generated by ChatGPT Really Correct? 写在最前面主要贡献这篇论文的创新点&#xff0c;为之后的论文提供了一些的启发未来研究的方向&#xff1a;改进自动化测试方法、创建测试输入生成器、探索新的评估数据集扩充方法&#xff0c;以及提高编程基准的精度。实验…