网站项目分析怎么做 方法,网站地图表现形式,网站开发成本核算,泰州做企业网站的哪里好✅作者简介#xff1a;大家好#xff0c;我是Leo#xff0c;热爱Java后端开发者#xff0c;一个想要与大家共同进步的男人#x1f609;#x1f609; #x1f34e;个人主页#xff1a;Leo的博客 #x1f49e;当前专栏#xff1a; Spring专栏 ✨特色专栏#xff1a; M…
✅作者简介大家好我是Leo热爱Java后端开发者一个想要与大家共同进步的男人 个人主页Leo的博客 当前专栏 Spring专栏 ✨特色专栏 MySQL学习 本文内容Spring学习笔记—JDK动态代理 ️个人小站 个人博客欢迎大家访问 个人知识库 知识库欢迎大家访问 学习参考 讲师孙帅老师课程孙哥说Spring5
1.前言
前面文章我们学习了关于Spring的IOC与AOP相关知识点在此之前我们主要学习Spring的一些核心概念IOC和AOP等等。我们之前学习了简单了解了AOP如何借助动态字节码技术来构建动态代理类。实现动态代理的方式不止一种。本次系列文章主要介绍两种JDK动态代理和CGlib动态代理主要主要介绍JDK动态代理。首先我们将着重了解JDK动态代理的核心原理和实际应用情境。好了话不多说让我们开始吧。
2.什么是JDK动态代理
大家都知道AOP底层是动态代理而Java中的动态代理有两种实现方式
基于 JDK 的动态代理基于 Cglib 的动态代理
这两者最大的区别在于基于 JDK 的动态代理需要被代理的对象有接口而基于 Cglib 的动态代理并不需要被代理对象有接口。
那么大家不禁要问Spring 中的 AOP 是怎么实现的是基于 JDK 的动态代理还是基于 Cglib 的动态代理那我们就先来里了解一下JDK动态代理。
在Spring框架中JDK动态代理是一种实现代理模式的技术用于在运行时动态地生成代理对象。它是基于Java的反射机制实现的。
JDK动态代理主要涉及两个核心接口InvocationHandler和Proxy。 InvocationHandler接口 InvocationHandler是一个接口它定义了一个方法invoke(Object proxy, Method method, Object[] args)。在使用JDK动态代理时我们需要实现InvocationHandler接口并在该方法中编写代理逻辑。 在invoke方法中代理对象的方法调用会被重定向到invoke方法中进行处理。我们可以在invoke方法中添加额外的逻辑如在方法调用前后做一些处理、拦截方法调用、修改方法参数等。通过invoke方法我们可以在不修改原始对象的情况下对其方法进行增强或增加额外的行为。 Proxy类 Proxy类是JDK提供的一个工具类用于创建代理对象。它提供了一个静态方法newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h)用于创建代理对象。 newProxyInstance方法接受三个参数 ClassLoader loader指定代理对象的类加载器。Class?[] interfaces指定代理对象要实现的接口。InvocationHandler h指定实现了InvocationHandler接口的对象用于处理方法调用。 newProxyInstance方法会返回一个实现了指定接口的代理对象该代理对象会将方法调用转发给指定的InvocationHandler对象。
我们可以通过这张流程图来清楚的了解JDK动态代理的执行流程 3.JDK动态代理的优缺点
3.1优点
JDK动态代理有以下优点
简单易用 使用JDK动态代理可以快速创建代理对象无需手动编写代理类减少了代码的编写量和维护成本。高效性能 JDK动态代理是通过Java的反射机制实现的底层通过字节码生成和动态类加载的方式来创建代理对象。相比于其他代理方式JDK动态代理的性能较高。纯Java实现 JDK动态代理是Java标准库的一部分不依赖第三方库或框架能够直接在Java应用中使用。松耦合 JDK动态代理可以对接口进行代理代理对象与目标对象之间通过接口进行交互实现了目标对象和代理对象的解耦。面向接口 JDK动态代理主要面向接口可以为接口中的所有方法提供代理对于实现了多个接口的对象可以为每个接口提供不同的代理逻辑。
3.2缺点
JDK动态代理也有一些缺点
只能代理接口 JDK动态代理只能代理实现了接口的目标对象对于没有实现接口的类无法进行代理。这限制了JDK动态代理的使用范围。无法直接访问目标对象的私有方法 JDK动态代理只能代理目标对象的公共方法无法直接访问目标对象的私有方法。如果需要对私有方法进行代理需要通过其他方式实现。创建代理对象的性能开销在创建代理对象时JDK动态代理需要通过反射和动态类加载来生成代理类这会带来一定的性能开销。但一旦代理对象创建完成后后续的方法调用性能与普通方法调用相当。
4.JDK动态代理的开发步骤
使用JDK动态代理时我们需要遵循以下步骤
创建一个实现了InvocationHandler接口的代理处理器类实现其中的invoke方法编写代理逻辑。使用Proxy类的newProxyInstance方法创建代理对象传入类加载器、接口数组和代理处理器对象。使用代理对象调用方法时方法调用会被重定向到代理处理器的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方法用于执行原始的方法调用。 5.JDK动态代理小结
总的来说JDK动态代理是一种简单易用、高效性能、纯Java实现的代理技术适用于面向接口的场景。它具有松耦合的特点能够将代理对象与目标对象解耦但同时也存在一些局限性如只能代理接口、无法直接访问私有方法等。根据具体的使用场景和需求选择合适的代理方式才能发挥代理的优势。
6.参考文献
https://www.itheima.com/news/20210525/165219.htmlhttps://blog.csdn.net/luoyoub/article/details/80101376https://spring.io/https://blog.csdn.net/qq_43266723/article/details/133488696
7.总结
以上便是本文的全部内容本人才疏学浅文章有什么错误的地方欢迎大佬们批评指正我是Leo一个在互联网行业的小白立志成为更好的自己。
如果你想了解更多关于Leo可以关注公众号-程序员Leo后面文章会首先同步至公众号。