zoukankan      html  css  js  c++  java
  • 面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?

    之前我已经写过了关于动态代理的两篇文章,本来以为这块应该没啥问题,没想到今天又被难住了…

    太难了!!!

    之前文章的链接:

    1. 动态代理学习(一)自己动手模拟JDK动态代理
    2. 动态代理学习(二)JDK动态代理源码分析

    动态代理学习(二)JDK动态代理源码分析中我已经讲JDK底层生成的字节码文件反编译成了java代码,如下:

    public final class proxy extends Proxy implements MyService {
        private static Method m1;
        private static Method m4;
        private static Method m2;
        private static Method m3;
        private static Method m0;
    
        public proxy(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 void test01() throws  {
            try {
                super.h.invoke(this, m4, (Object[])null);
            } catch (RuntimeException | Error var2) {
                throw var2;
            } catch (Throwable var3) {
                throw new UndeclaredThrowableException(var3);
            }
        }
    
        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 test02(String var1) throws  {
            try {
                super.h.invoke(this, m3, new Object[]{var1});
            } catch (RuntimeException | Error var3) {
                throw var3;
            } catch (Throwable var4) {
                throw new UndeclaredThrowableException(var4);
            }
        }
    
        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"));
                m4 = Class.forName("com.dmz.proxy.target.MyService").getMethod("test01");
                m2 = Class.forName("java.lang.Object").getMethod("toString");
                m3 = Class.forName("com.dmz.proxy.target.MyService").getMethod("test02", Class.forName("java.lang.String"));
                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的动态代理为什么要继承Proxy这个类呢?
    在之前的文章中提到过:我们可以发现代理类并没有使用Proxy中的什么属性或者方法(虽然使用了InvocationHandler对象,但是也可以在生成class之初就将InvocationHandler放入到代理类中)

    这样看来,不继承这个Proxy确实也能实现动态代理。

    如果要回答为什么要使用Proxy这个类,我们不妨假设所有的代理类都不继承这个类,那么会怎么样呢?

    这样的话,代理类就要变成这样子

    // 去 extends Proxy
    public final class proxy implements MyService {
        private static Method m1;
        private static Method m4;
        private static Method m2;
        private static Method m3;
        private static Method m0;
        // 这个时候代理类就需要自己持有一个InvocationHandler对象了
    	private InvocationHandler h;
        public proxy(InvocationHandler h){
            // super(var1);
            this.h = h;
        }
    	// ......
    }
    

    ​ 这样确实还是能实现代理类的所有功能,但是我们会发现,在生成每一个代理类的时候都需要往生成的字节码中写入这么一段。相比于继承的方式这种形式写入的内容要多一些,这也意味着消耗的性能要高一些。
    所以基于此我们可以总结出第一个原因:
    基于继承的方式可以减少生成代理类时产生的性能消耗
    ​ 如果仅仅基于上面的原因没办法说服你的话,那么不要急,继续往下看,我们思考这么一种场景,如果有一天我需要对所有的代理类进行某一种处理的话,我们该如何知道这个类是一个经过代理产生的类呢?
    如果是基于上面这种方式的话,我能想到的办法只有一种

    1. 遍历所有的类
    2. 判断该类中是否持有一个InvocationHandler对象

    但是难道只有代理类能持有一个InvocationHandler吗?很显然不是的,我们也可以自己定义一个类,也能持有一个InvocationHandler。

    但是如果通过继承Proxy的方式的话,我们只需要

    1. 遍历所有类
    2. 判断它是否是一个Proxy(instance of Prxoy)

    这样就能完成我们的需求

    最后我想说的是,我觉得Jdk自所以要这么进行实现,是因为它将所有的代理类进行了一层抽象,为所有的代理类定义了一个父类。所有的代理类都有一个共同点---------持有一个InvocationHandler。所以基于此,抽象出一个父类Proxy。同时又由于JDK的动态代理就是基于接口代理来设计的,继承一个父类并没有违背它设计的初衷。因此Proxy就作为所有代理类的父类诞生了!!!

    本文只是个人看法,欢迎各路大神指正!

    码字不易,求个赞吧!

  • 相关阅读:
    Linux系统挂载NTFS移动硬盘
    ActiveReport报表开发谈谈ActiveReport的中文化问题
    硬件接口开发之USB电话录音盒来电显示
    如何使用正则表达式进行QQ校友的数据采集
    硬件接口开发之Modem来电显示
    关于MSHTML控件使用的问题
    【转】ISession接口介绍
    发送带嵌入图片邮件之SMTP实现和ESMTP实现
    C#进行MapX二次开发之地图搜索
    Database2Sharp混淆处理之经验分享(国庆专辑,祝福我们的祖国)
  • 原文地址:https://www.cnblogs.com/daimzh/p/12854382.html
Copyright © 2011-2022 走看看