首页 > 其他分享 >动态代理原理分析

动态代理原理分析

时间:2025-01-08 20:29:33浏览次数:3  
标签:var1 var10000 Object 代理 public CGLIB 原理 动态 final

jdk动态代理

        jdk动态代理是jre提供给我们的类库,可以直接使用,不依赖第三方。

代码示例

        接口类

public interface ICar {
    void color();
}

        接口实现类

public class BSJCar implements ICar{
    @Override
    public void color() {
        System.out.println("这是一辆黑色的车");
    }
}

        测试代理

public class Test {
    public static void main(String[] args) {
        BSJCar bsjCar = new BSJCar();
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        ICar proxyCar = (ICar) Proxy.newProxyInstance(bsjCar.getClass().getClassLoader(), bsjCar.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理前增强---");
                Object invoke = method.invoke(bsjCar, args);
                System.out.println("代理后增强---");
                return proxy;
            }
        });
        proxyCar.color();
    }
}

方法使用说明

Proxy.newProxyInstance的三个参数说明

  1. ClassLoader loader  获取被代理类类加载器

  2. Class<?>[] interfaces  获取被代理类的实现接口的数组

  3. InvocationHandler h   在invoke方法中对方法做增强处理。

invoke方法的三个参数说明

  1. Object proxy 当前代理对象

  2. Method method  方法对象(调用被代理对象)

  3. Object[] args  方法传递的参数

原理解析

        通过加上以下一行代码就可以把jdk动态代理时候生产的代理对象输出目录中。

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

        生成的代理对象如下:

public final class $Proxy0 extends Proxy implements ICar {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void color() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.example.test.proxy.jdk.ICar").getMethod("color");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

从代理类分析可得JDK动态是怎么增强被代理类的

  1. 代理类继承了Proxy,实现了被代理类接口

  2. 重写了被代理类接口中的所有方法

  3. 代理类中的方法调用了父类(Proxy对象)中持有的h对象(InvocationHandler)的invoke方法。

 所以当我们调用color()方法时其实调用的是Proxy对象的InvocationHandler的invoke方法

  public final void color() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

cglib动态代理

        要导入cglib第三方库,要求被代理类不能是最终类,即不能用final修饰,如String类。

代码示例

        被代理类

@Data
public class XMPhone {
    private Integer money;

    public void color() {
        System.out.println("这是黑色的手机");
    }
}

        测试类

public class Test {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.
                DEBUG_LOCATION_PROPERTY, System.getProperty("user.dir"));
        XMPhone phone = (XMPhone) Enhancer.create(XMPhone.class, new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("代理前增强---");
                methodProxy.invokeSuper(o, objects);
                System.out.println("代理后增强---");
                System.out.println(o.getClass());
                return o;
            }
        });
        phone.color();
    }
}

方法使用说明

Enhancer.create的2个参数

  1. Class type 被代理类的class类型
  2. Callback callback 一个Callback接口,我们通常使用MethodInterceptor接口,继承了Callback接口

intercept方法的参数

  1. Object var1 代理类对象
  2. Method var2 被代理类方法对象(被拦截的方法)
  3. Object[]  var3 方法用到的参数数组
  4. MethodProxy var4 cglib方法对象

原理解析

        CGLib动态代理生成的代理对象

public class XMPhone$$EnhancerByCGLIB$$ca64c8f6 extends XMPhone implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$equals$0$Method;
    private static final MethodProxy CGLIB$equals$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$toString$1$Method;
    private static final MethodProxy CGLIB$toString$1$Proxy;
    private static final Method CGLIB$hashCode$2$Method;
    private static final MethodProxy CGLIB$hashCode$2$Proxy;
    private static final Method CGLIB$color$3$Method;
    private static final MethodProxy CGLIB$color$3$Proxy;
    private static final Method CGLIB$canEqual$4$Method;
    private static final MethodProxy CGLIB$canEqual$4$Proxy;
    private static final Method CGLIB$clone$5$Method;
    private static final MethodProxy CGLIB$clone$5$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.example.test.proxy.cglib.XMPhone$$EnhancerByCGLIB$$ca64c8f6");
        Class var1;
        CGLIB$clone$5$Method = ReflectUtils.findMethods(new String[]{"clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods())[0];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "color", "()V", "canEqual", "(Ljava/lang/Object;)Z"}, (var1 = Class.forName("com.example.test.proxy.cglib.XMPhone")).getDeclaredMethods());
        CGLIB$equals$0$Method = var10000[0];
        CGLIB$equals$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$0");
        CGLIB$toString$1$Method = var10000[1];
        CGLIB$toString$1$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$1");
        CGLIB$hashCode$2$Method = var10000[2];
        CGLIB$hashCode$2$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$2");
        CGLIB$color$3$Method = var10000[3];
        CGLIB$color$3$Proxy = MethodProxy.create(var1, var0, "()V", "color", "CGLIB$color$3");
        CGLIB$canEqual$4$Method = var10000[4];
        CGLIB$canEqual$4$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "canEqual", "CGLIB$canEqual$4");
    }

    final boolean CGLIB$equals$0(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$0$Method, new Object[]{var1}, CGLIB$equals$0$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$1() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$1$Method, CGLIB$emptyArgs, CGLIB$toString$1$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$2() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$2$Method, CGLIB$emptyArgs, CGLIB$hashCode$2$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final void CGLIB$color$3() {
        super.color();
    }

    public final void color() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$color$3$Method, CGLIB$emptyArgs, CGLIB$color$3$Proxy);
        } else {
            super.color();
        }
    }

    final boolean CGLIB$canEqual$4(Object var1) {
        return super.canEqual(var1);
    }

    protected final boolean canEqual(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$canEqual$4$Method, new Object[]{var1}, CGLIB$canEqual$4$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.canEqual(var1);
        }
    }

    final Object CGLIB$clone$5() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch (var10000.hashCode()) {
            case -628880078:
                if (var10000.equals("color()V")) {
                    return CGLIB$color$3$Proxy;
                }
                break;
            case -508378822:
                if (var10000.equals("clone()Ljava/lang/Object;")) {
                    return CGLIB$clone$5$Proxy;
                }
                break;
            case 437408081:
                if (var10000.equals("canEqual(Ljava/lang/Object;)Z")) {
                    return CGLIB$canEqual$4$Proxy;
                }
                break;
            case 1826985398:
                if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                    return CGLIB$equals$0$Proxy;
                }
                break;
            case 1913648695:
                if (var10000.equals("toString()Ljava/lang/String;")) {
                    return CGLIB$toString$1$Proxy;
                }
                break;
            case 1984935277:
                if (var10000.equals("hashCode()I")) {
                    return CGLIB$hashCode$2$Proxy;
                }
        }

        return null;
    }

    public XMPhone$$EnhancerByCGLIB$$ca64c8f6() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        XMPhone$$EnhancerByCGLIB$$ca64c8f6 var1 = (XMPhone$$EnhancerByCGLIB$$ca64c8f6)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        XMPhone$$EnhancerByCGLIB$$ca64c8f6 var10000 = new XMPhone$$EnhancerByCGLIB$$ca64c8f6();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        XMPhone$$EnhancerByCGLIB$$ca64c8f6 var10000 = new XMPhone$$EnhancerByCGLIB$$ca64c8f6();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        XMPhone$$EnhancerByCGLIB$$ca64c8f6 var10000 = new XMPhone$$EnhancerByCGLIB$$ca64c8f6;
        switch (var1.length) {
            case 0:
                var10000.<init>();
                CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
                return var10000;
            default:
                throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch (var1) {
            case 0:
                var10000 = this.CGLIB$CALLBACK_0;
                break;
            default:
                var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch (var1) {
            case 0:
                this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
            default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

从代理类分析可得是CGLIB动态是怎么增强的被代理类

  1. 代理类继承了被代理类,实现了Factory接口
  2. 代理类持有 MethodInterceptor对象
  3. 代理类重写了被代理类的非final、private方法;重写方法会先判断MethodInterceptor是否存在,存在调用intercept方法,否则调用父类的方法。
  4. 构建了cglib方法。格式:CGLIB$父类方法名$数字,方法里面调用了父类的方法。

所以当我们调用color方法时,其实调用的是MethodInterceptor.intercept()方法。这个方法中

CGLIB$color$3$Proxy对象就是CGLIB$color$3()方法的对象,里面调用父类的方法。

    final void CGLIB$color$3() {
        super.color();
    }

    public final void color() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$color$3$Method, CGLIB$emptyArgs, CGLIB$color$3$Proxy);
        } else {
            super.color();
        }
    }

标签:var1,var10000,Object,代理,public,CGLIB,原理,动态,final
From: https://blog.csdn.net/qq_46189247/article/details/145013679

相关文章

  • 乘积最大子数组(动态规划)
    给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。 测试用例的答案是一个 32-位 整数。 示例1:输入:nums=[2,3,-2,4]输出:6解释: 子数组[2,3]有最大乘积6。示例2:输入:nums=[-2......
  • 最长递增子序列(动态规划)
    给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 示例1:输入:nums=[10,9,2,5,3,7,101,18]输出:4解释:最长递增子序......
  • 【游戏设计原理】53 - 解决问题的障碍
    1.分析并总结原理核心观点游戏本质是一系列问题解决的过程,通过设计巧妙的问题和决策场景,游戏能激发玩家的兴趣和投入感。然而,当问题解决的过程被阻碍时,会降低玩家的体验甚至让他们放弃游戏。文中提到的四种障碍反映了玩家在面对复杂问题时可能遇到的心理和认知问题:功能......
  • 【网络协议】动态路由协议
    前言本文将概述动态路由协议,定义其概念,并了解其与静态路由的区别。同时将讨论动态路由协议相较于静态路由的优势,学习动态路由协议的不同类别以及无类别(classless)和有类别(classful)的特性等。【网络协议】静态路由详解文章目录前言正文定义分类路由协议的运行原理动态路......
  • 单词拆分(动态规划)
    给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例1:输入:s="leetcode",wordDict=["leet","code"]输出:true......
  • 【信阳师范大学】计算机网络原理第二章
    【信阳师范大学】计算机网络原理第二章作业更多期末考试资料请查看博客:https://blog.x1a0yu.top/一.填空题(共9题,47分)1.(填空题)计算机网路的物理层的主要任务是描述为确定与传输媒体的接口有关的一些特性,这些特性主要包括机械特性、_________________、_______________......
  • 零钱兑换(动态规划)
    给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为每种硬币的数量是无限的。 示例 1:输入:coins=[1,2,5],amount=11......
  • 完全平方数(动态规划)
    给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。示例 1:输入:n=12输出:3解释:12=4+4+4示例2:输入:n=13......
  • 二维动态规划2
    [Algo]二维动态规划21.不同的子序列//4.不同的子序列//https://leetcode.cn/problems/distinct-subsequences/longnumDistinct(strings,stringt){intn=s.length(),m=t.length();vector<vector<long>>dp(n+1,vector<long>(m+1));//dp[i]......
  • Java HashMap 深度解析:底层原理、源码剖析与面试必备知识
    1.HashMap概述HashMap是Java集合框架中最常用的数据结构之一,基于哈希表(HashTable)实现。它以键值对(Key-Value)存储数据,允许null键和null值,且无序。1.1HashMap的特性基于哈希表(HashTable)实现允许null键和null值非线程安全默认初始容量16,负载因子0.75JDK1......