iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >通俗易懂 快速理解 JDK动态代理 和 cglib动态代理
  • 258
分享到

通俗易懂 快速理解 JDK动态代理 和 cglib动态代理

javaspring 2023-10-21 19:10:27 258人浏览 泡泡鱼
摘要

动态代理的实现方案有两种,JDK动态代理和CGLIB动态代理,区别在于jdk自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。 JDK动态代理:JDK原生的实现方式,需要被代理的

  • 动态代理的实现方案有两种,JDK动态代理CGLIB动态代理,区别在于jdk自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。

  • JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。

  • cglib动态代理:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口。(CGLIB 通过动态生成一个需要被代理类的子类(即被代理类作为父类),该子类重写被代理类的所有不是 final 修饰的方法,并在子类中采用方法拦截的技术拦截父类所有的方法调用,进而织入横切逻辑。)

没有实现接口或者不需要实现接口的类,我们可以通过cglib动态代理对它进行代理。

基于cglib实现的动态代理需要引入第三方cglib库,之后我们可以实现基于子类的动态代理。

使用cglib实现的动态代理也有一个约束条件,就是被代理类不能被final修饰,

​使用cglib实现的动态代理核心是Enhancer类,仔细观察我们会发现cglib动态代理的实现过程和JDK实现动态代理的过程极其类似。

提示:务必仔细看代码注释!!!注释上有很详细的解释

导航栏:

cglib动态代理

注意:这里需要引入依赖:cglib 2.1_3.jar
(如果不是Maven项目,也可以手动导入cglib的jar包进行测试

<dependency><groupId>cglibgroupId><artifactId>cglibartifactId><version>2.1_3version>dependency>

测试demo结构:

在这里插入图片描述

代码:

被代理类 Star:

package com.tong;public class Star {    public void sing() {        System.out.println("唱.......");    }    public void dance() {        System.out.println("跳......");    }}

被代理类 ChineseCartoon:

package com.tong;public class ChineseCartoon {    public String person(String arg1, String arg2) {        if (arg1.equals("青莲地心火") && arg2.equals("陨落心炎")) {            System.out.println("斗破苍穹---萧炎");            return "萧炎";        }        return "123";    }}
  • 这里的create方法有两个参数,分别是Class typeCallback callback
  • 其中Class type是指被代理类的字节码文件,因为有了被代理类的字节码后(即:被代理类的运行时类),就相当于可以获取被代理类的全部信息
  • Callback callback是用于提供增强代码的,一般都是写一个接口的实现,通常情况下都是匿名内部类,这里我们一般不适用Callback接口,而是使用它的子接口MethodInterceptor的实现类。

生成代理类的工厂类 ProxyFactory:

package com.tong;import com.oracle.jrockit.jfr.Producer;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Arrays;public class ProxyFactory {    private Object target;    public ProxyFactory(Object target) {        this.target = target;    }    // 通过该方法可以生成任意目标类所对应的代理类    public static Object getProxy(Object target) {        // proxy就是我们创建的代理对象,这个对象可以执行被代理类中所有的方法,并且我们可以在代理对象中对被代理类的方法进行增强        Object proxy = Enhancer.create(target.getClass(), new MethodInterceptor() {                        @Override            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) {                Object result = null;                try {                    // 提供增强代码                    System.out.println("[动态代理][日志] " + method.getName() + ",参数:" + Arrays.toString(objects));                    //通过反射调用method对象所表示的方法,并获取该方法的返回值                    //在具有指定参数的指定对象上调用此method对象表示的底层方法。                    //此处就是通过target来确定调用的是具体哪个类中的方法                    result = method.invoke(target, objects);                    System.out.println("[动态代理][日志] " + method.getName() + ",结 果:" + result);                } catch (Exception e) {                    e.printStackTrace();                    System.out.println("[动态代理][日志] " + method.getName() + ",异常:" + e.getMessage());                } finally {                    System.out.println("[动态代理][日志] " + method.getName() + ",方法执行完毕");                }                return result;            }        });        // 返回代理对象        return proxy;    }}

测试类 ProxyTest:

package com.tong;import org.junit.Test;public class ProxyTest {    @Test    public void test(){        Star star = new Star();                Star proxy = (Star)ProxyFactory.getProxy(star);        proxy.sing();        System.out.println("-----------------分割线------------------");        proxy.dance();        System.out.println("-----------------分割线------------------");        // 创建被代理类的对象        ChineseCartoon chineseCartoon = new ChineseCartoon();        // 获取代理对象        ChineseCartoon proxy1 = (ChineseCartoon)ProxyFactory.getProxy(chineseCartoon);        proxy1.person("青莲地心火","陨落心炎");    }}

运行结果:

在这里插入图片描述

结论:

当测试类中通过父类的引用proxy调用了方法proxy.sing()时,由于父类 Star类子类(动态代理类 给继承了【即:代理子类已经重写了父类中的sing()】。所以,当使用父类引用proxy调用sing()方法时,实际执行的是动态代理类 (子类) 中的 sing()方法。而在这个动态代理类重写的方法中,又会去调用 MethodInterceptor接口的匿名实现类中重写的 intercept() 方法对父类方法的调用进行拦截【即:在子类中采用方法拦截的技术拦截父类所有的方法调用】。在这个方法中,可以实现对被代理方法的功能增强【即:织入横切逻辑】,最后通过method.invoke()反射技术来调用父类中的方法。

❤ 由于我们的代理类工厂中有参构造的参数是Object类型的,所以最终实现的效果是动态生成代理类对象。

tips:父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的。

MethodInterceptor接口的匿名实现类中重写的 intercept() 方法的官方文档解释:
在这里插入图片描述

JDK动态代理

代码:

接口 Calculator :

package com.tong.spring.calculator;public interface Calculator {    int add(int i, int j);    int sub(int i, int j);    int mul(int i, int j);    int div(int i, int j);}

接口实现类 CalculatorImpl:

package com.tong.spring.calculator;public class CalculatorImpl implements Calculator{    @Override    public int add(int i, int j) {        int result = i + j;        System.out.println("方法内部 result = " + result);        return result;    }    @Override    public int sub(int i, int j) {        int result = i - j;        System.out.println("方法内部 result = " + result);        return result;    }    @Override    public int mul(int i, int j) {        int result = i * j;        System.out.println("方法内部 result = " + result);        return result;    }    @Override    public int div(int i, int j) {        int result = i / j;        System.out.println("方法内部 result = " + result);        return result;    }}

生产代理对象的工厂类 ProxyFactory:

public class ProxyFactory {    private Object target;    public ProxyFactory(Object target) {        this.target = target;    }    // 通过该方法可以生成任意目标类所对应的代理类    public Object getProxy(){                //第一个参数,获取代理对象的类加载器 (类加载器是程序中默认的类加载器,一般来说,Java应用的类都是由它来完成加载。所以,此处通过代理类或者被代理类获取到的类加载器都是同一个,或通过任何一个类获取到的类加载器都是同一个。)        ClassLoader classLoader = this.getClass().getClassLoader();        //第二个参数,被代理对象实现的所有接口数组        Class<?>[] interfaces = target.getClass().getInterfaces();        //当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用        //代理实例的调用处理程序        //第三个参数InvocationHandler的实现类,这里用了匿名内部类的方式        InvocationHandler invocationHandler = new InvocationHandler() {             //重写InvocationHandler的invoke方法,他有三个参数可以供我们使用            @Override            public Object invoke(Object proxy, Method method, Object[] args){                                Object result = null;                try {                    //method.getName(): 返回此method对象表示的方法的名称,作为字符串                    System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));                     //通过反射调用method对象所表示的方法,并获取该方法的返回值                     //在具有指定参数的指定对象上调用此method对象表示的底层方法。                     //此处就是通过target来确定调用的是具体哪个类中的方法                     result = method.invoke(target, args);                     System.out.println("[动态代理][日志] "+method.getName()+",结 果:"+ result);                  } catch (Exception e) {                   e.printStackTrace();                   System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());                  } finally {                      System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");                  }                  return result;               }               };         //返回指定接口的代理类的实例,该实例将方法调用分派给指定的调用处理程序。        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);      }}         

测试类 ProxyTest:

package com.tong.proxy;import com.tong.spring.calculator.Calculator;import com.tong.spring.calculator.CalculatorImpl;import com.tong.spring.calculator.proxy.ProxyFactory;import org.junit.Test;public class ProxyTest {    @Test    public void testDynamicProxy(){        ProxyFactory factory = new ProxyFactory(new CalculatorImpl());        Calculator proxy = (Calculator) factory.getProxy();        //创建好了代理对象,代理对象就可以执行被代理类实现的接口的方法;当通过代理类的对象发起对被重写的方法的调用时,都会转换为对调用处理器实现类中的invoke方法的调用,invoke方法中就可以对被代理类进行功能增强.        proxy.add(1, 5);//        proxy.div(1,0);    }}

运行结果:

在这里插入图片描述

结论:

通过factory.getProxy()创建好了代理对象后,代理对象proxy就可以执行被代理类实现的接口的方法;当通过代理类的对象发起对被重写的方法的调用时,都会转换为对调用处理器实现类中的invoke方法的调用,invoke方法中就可以对被代理类进行功能增强并通过反射调用被代理的同名方法。

编写不易,有帮到各位朋友理解的,点个赞再走哦!๑(≥▽≤)๑

来源地址:https://blog.csdn.net/weixin_43935152/article/details/130514814

--结束END--

本文标题: 通俗易懂 快速理解 JDK动态代理 和 cglib动态代理

本文链接: https://www.lsjlt.com/news/434027.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 通俗易懂 快速理解 JDK动态代理 和 cglib动态代理
    动态代理的实现方案有两种,JDK动态代理和CGLIB动态代理,区别在于JDK自带的动态代理,必须要有接口,而CGLIB动态代理有没有接口都可以。 JDK动态代理:JDK原生的实现方式,需要被代理的...
    99+
    2023-10-21
    java spring
  • jdk动态代理和cglib动态代理详解
    目录静态代理基于继承的方式实现静态代理基于聚合的方式实现静态代理继承与聚合方式实现的静态代理对比动态代理JDK动态代理如何实现一个HashMap的动态代理类?Cglib动态代理JDK...
    99+
    2024-04-02
  • spring cglib 与 jdk 动态代理
    1. 概述JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理Cglib动态代理是 利用asm开源包 把被代理类的class文件加载进来 通过修改其字节码生成子类来处...
    99+
    2023-05-31
    spring cglib jdk
  • JDK和CGLib动态代理怎么实现
    本篇内容介绍了“JDK和CGLib动态代理怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言:动态代理是一种常用的设计模式,广泛应用...
    99+
    2023-06-02
  • 基于jdk动态代理和cglib动态代理实现及区别说明
    目录jdk动态代理和cglib动态代理实现及区别jdk动态代理实现cglib动态代理区别总结jdk动态代理和cglib动态代理实现及区别 代理模式是一种设计模式,提供了对目标对象额外...
    99+
    2023-05-19
    jdk动态代理 cglib动态代理 jdk和cglib动态代理区别
  • 静态代理、jdk、cglib动态代理 搞不清? 看这个文章就懂了
    一、代理模式 代理模式是一种比较好的理解的设计模式。简单来说就是 : 我们使用代理对象来增强目标对象(target obiect),这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。将核心业务代码和非核心的公共代...
    99+
    2023-08-30
    java jdk 代理模式 面试
  • java动态代理(jdk与cglib)详细解析
    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息...
    99+
    2022-11-15
    java jdk cglib
  • Java反射(JDK)与动态代理(CGLIB)详解
    目录一、反射二、动态代理1、JDK代理2、CGLIB代理3、JDK代理与CGLIB代理对比总结一、反射 概念:在运行状态中,对于任意的一个类,都能够知道这个类的所有字段和方法,对任意...
    99+
    2024-04-02
  • java代理模式(静态代理、动态代理、cglib代理)
    目录代理模式静态代理代码接口被代理对象代理对象测试动态代理代码:接口目标对象代理对象测试cglib代理代码:目标对象代理对象测试应用总结代理模式 代理模式(Proxy Pattern...
    99+
    2024-04-02
  • Spring中JDK和cglib动态代理原理的示例分析
    这篇文章给大家分享的是有关Spring中JDK和cglib动态代理原理的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Java代理介绍Java中代理的实现一般分为三种:JDK静态代理、JDK动态代理以及C...
    99+
    2023-06-02
  • Java——JDK动态代理
    1.动态代理 1.1什么是动态代理? 动态代理(理解) 基于反射机制 举个例子,生活中一般在打官司的时候都会请代理律师,为什么要请律师呢?是因为开庭的时候大部人对于打官司没有经验,只会说出自己案件的陈述,并不会根据法律等争取自己权益...
    99+
    2023-08-31
    java 开发语言
  • Java 动态代理你真的懂了吗(动态和代理)
    好几天不写文章,今天来写一篇,从之前的计划表上看到还有关于java的动态代理没写,这个技术平常用的少,也不是特别好理解,今天补上这篇,希望能讲明白,不至于像我一样迷茫好久,开始吧 动...
    99+
    2024-04-02
  • Java cglib动态代理原理分析
    目录一、cglib 动态代理示例  二、代理类分析 三、Fastclass 机制分析 本文分下面三个部分来分析cglib动态代理的原理。 cglib&n...
    99+
    2024-04-02
  • Java JDK与cglib动态代理有哪些区别
    本篇内容主要讲解“Java JDK与cglib动态代理有哪些区别”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java JDK与cglib动态代理有哪些区别”吧!一、说明sp...
    99+
    2023-07-05
  • Spring之AOP两种代理机制对比分析(JDK和CGLib动态代理)
    目录Spring AOP两种代理机制对比JDK动态代理CGLib动态代理SpringAOP两种代理原理SpringAOP代理JDK动态代理CGLIB代理两者对比使用注意总结Sprin...
    99+
    2023-05-19
    Spring AOP AOP代理机制 JDK动态代理 CGLib动态代理
  • java jdk动态代理详解
    jdk动态代理要对一个类进行代理,被代理的类必须实现至少一个接口,并且只有接口中的方法才能被代理。 jdk实现动态代理一般分为三步: 1. 编写接口和实现类。 2. 写一个处理器,该...
    99+
    2022-11-15
    java jdk 动态代理
  • 深入浅析java 中的JDK与cglib动态代理
    这篇文章将为大家详细讲解有关深入浅析java 中的JDK与cglib动态代理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。java 动态代理实例详解1.jdk动态代理 package com...
    99+
    2023-05-31
    java jdk cglib
  • 深入理解java动态代理的两种实现方式(JDK/Cglib)
    什么是代理模式?代理模式:在调用处不直接调用目标类进行操作,而是调用代理类,然后通过代理类来调用目标类进行操作。在代理类调用目标类的前后可以添加一些预处理和后处理操作来完成一些不属于目标类的功能。为什么要使用代理模式?通过代理模式可以实现对...
    99+
    2023-05-31
    cglib jdk java
  • Java基础之动态代理Cglib详解
    目录一、前言二、服务三、代理工厂四、结果一、前言 经测试,jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适...
    99+
    2024-04-02
  • 基于JDK动态代理原理解析
    目录1、回顾一下JDK动态代理的核心参数2、实现一个简单的动态代理①、定义接口Subject②、定义接口的实现类RealSubject③、定义代理对象创建工厂④、创建测试类,为tar...
    99+
    2023-05-18
    JDK动态代理原理 JDK动态代理 动态代理原理
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作