JDK动态代理详细解析

 更新时间:2023年11月27日 10:13:21   作者:一码评川  
这篇文章主要介绍了JDK动态代理详细解析,在Java的动态代理机制中,有两个重要的类和接口,一个是InvoInvocationHandler(接口)、Proxy(类),这一个类和接口是我们动态代理所必须用到的,需要的朋友可以参考下

一、说明

在Java的动态代理机制中,有两个重要的类和接口,一个是InvoInvocationHandler(接口)、Proxy(类),这一个类和接口是我们动态代理所必须用到的。

在这里插入图片描述

优点:

  • 对于实现了接口的类,可以直接使用基于接口的动态代理进行代理,非常方便
  • 代理类和被代理类都必须实现同一个接口,能够实现对被代理对象的方法调用进行统一管理。
  • 性能上:在老版的jdk,jdk代理生成的类速度快,通过反射调用慢,cglib是jdk代理速度的10倍左右,jdk在版本每次升级都会有很大的性能提升,cglib停滞不前,jdk7 8的动态代理性能在1万次实验中比cglib要快20%左右
  • jdk动态代理如果目标类未实现接口则无法代理,cglib是通过继承的方式来动态代理,若目标类被final关键字修饰,则无法使用cglib做动态代理

缺点:

  • 只能代理实现了接口的类,对于没有实现接口的类无法使用此种方式进行代理。
  • jdk动态代理只提供实现接口的目标类代理,不支持没有实现接口的目标类的代理。如果目标类没有实现接口,只能用cglib代理

二、主要类方法的说明

InvocationHandler接口

每个动态代理类都必须实现InvocationHandler接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler接口的invoke方法来进行调用。

InvocationHandler接口的invoke方法

  • Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  • proxy:  - 指代我们所代理的那个真实对象
  • method: - 指代的是我们所要调用真实对象的某个方法的Method对象
  • args:  - 指代的是调用真实对象某个方法时接受的参数

**proxy存在的意义:**

1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName())。

2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。

Proxy 类

Proxy类的作用就是用来动态创建一个代理类对象的类,它提供了许多的方法,但是我们用的最多的就是newProxyInstance这个方法

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
  • loader:   一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  • interfaces:  一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
  • h:   一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

打印代理的类:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

三、关键步骤

创建InvocationHandler实现类

public class MapperProxy<T> implements InvocationHandler {
      private Class<T> proxyInterface;
    //这里可以维护一个缓存,存这个接口的方法抽象的对象
    MapperProxy(Class<T> proxyInterface){
        this.proxyInterface = proxyInterface;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前...");
        Constructor constructor  = proxyInterface.getConstructor();
        Object o =  constructor.newInstance();
        method.invoke(o,args);
        System.out.println("执行后");
        return null;
    }
}

通过 Proxy.newProxyInstance() 创建代理实例

 Fly fly = (Fly) Proxy.newProxyInstance(MyFly.class.getClassLoader(),new Class[]{Fly.class, Fly.Fly2.class},new MapperProxy<>(MyFly.class));

在这里插入图片描述

-  创建代理类-   Class<?> cl = getProxyClass0(loader, intfs);

-  获取有参构造器  Constructor<?> cons = cl.getConstructor(constructorParams);这里的参数就是InvocationHandler

-  通过构造器创建代理实例-参数就是方法的第三个参数

分析生成的代理类

在这里插入图片描述

在这里插入图片描述

结论 

  • 代理类会继承Proxy ,这里也就解释了为什么通过JDK生成的代理无法代理非接口实现类了
  • 代理类实现了传入的所有接口类型

调用代理类的doFly()

这里会调用 super.h.invoke(this, m3, (Object[])null);

super.h就是我们再创建代理对象是传入的MapperProxy,所有这里会执行MapperProxy.invoke方法(在这里我们就可动态的对该执行方法进行增强)

在这里插入图片描述

到此这篇关于JDK动态代理详细解析的文章就介绍到这了,更多相关JDK动态代理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决IDEA中 Ctrl+ALT+V这个快捷键无法使用的情况

    解决IDEA中 Ctrl+ALT+V这个快捷键无法使用的情况

    这篇文章主要介绍了解决IDEA中 Ctrl+ALT+V这个快捷键无法使用的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • 轻松掌握Java模板模式

    轻松掌握Java模板模式

    这篇文章主要帮助大家轻松掌握Java模板模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • idea 查看一个类的所有子类以及子类的子类并以层级关系显示

    idea 查看一个类的所有子类以及子类的子类并以层级关系显示

    这篇文章主要介绍了idea 查看一个类的所有子类以及子类的子类并以层级关系显示,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • Java如何使用Query动态拼接SQL详解

    Java如何使用Query动态拼接SQL详解

    这篇文章主要给大家介绍了关于Java如何使用Query动态拼接SQL的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Java实现拖拽文件上传dropzone.js的简单使用示例代码

    Java实现拖拽文件上传dropzone.js的简单使用示例代码

    本篇文章主要介绍了Java实现拖拽文件上传dropzone.js的简单使用示例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-07-07
  • Spring中propagation的7种事务配置及说明

    Spring中propagation的7种事务配置及说明

    这篇文章主要介绍了Spring中propagation的7种事务配置及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Springboot的启动原理详细解读

    Springboot的启动原理详细解读

    这篇文章主要介绍了Springboot的启动原理详细解读,springboot项目一般都是打包成jar包直接运行main方法启动,当然也可以跟传统的项目一样打包war包放在tomcat里面启动.那么springboot怎么直接通过main方法启动呢,需要的朋友可以参考下
    2023-11-11
  • 简单实现java数独游戏

    简单实现java数独游戏

    这篇文章主要教大家如何简单实现java数独游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Java报错:Error:java: 程序包org.springframework.boot不存在解决办法

    Java报错:Error:java: 程序包org.springframework.boot不存在解决办法

    建完springboot项目时,点击启动,有可能会报错,下面这篇文章主要给大家介绍了关于Java报错:Error:java: 程序包org.springframework.boot不存在的解决办法,需要的朋友可以参考下
    2024-02-02
  • Springboot详解如何整合使用Thymeleaf

    Springboot详解如何整合使用Thymeleaf

    这篇文章主要分享了Spring Boot整合使用Thymeleaf,Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMarker等传统引擎,关于其更多相关内容,需要的小伙伴可以参考一下
    2022-06-06

最新评论