• 代理模式-3(手写实现JDK动态代理)


      不仅知其然,还得知其所以然。既然JDK 动态代理功能如此强大,那么他是如何实现的呢?

      我么都知道 JDK 动态代理采用字节重组,重组生成对象来替代原始对象,以达到动态代理的目的。JDK 动态代理生成对象的步骤如下:

      (1)获取被代理对象的引用,并且获取他的所有接口,反射获取。

      (2)JDK 动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口。

      (3)动态生成的 Jave 代码,新加的业务逻辑方法由一定的逻辑代码调用。

      (4)编译新生成的 Java 代码 .class 文件。

      (5)重新加载到JVM中运行。

      以上过程就叫做字节码重组。JDK 中有一个规范,在ClassPath 下只要是 $ 开头的 .class 文件,一般都是自动生成的。那么我们可以将内存中的对象字节码通过文件流输出到一个新的 .calss 文件,然后利用反编译工具查看其源代码。

      

    package com.xq.design.proxy;
    
    import com.xq.design.proxy.dynamicproxy.jdkproxy.Customer;
    import com.xq.design.proxy.dynamicproxy.jdkproxy.JDKMeipo;
    import com.xq.design.proxy.dynamicproxy.jdkproxy.Person;
    import org.junit.jupiter.api.Test;
    import sun.misc.ProxyGenerator;
    
    import java.io.FileOutputStream;
    
    public class JDKProxyTest {
    
        @Test
        void JDKProxyTest(){
            try{
                Person obj =(Person) new JDKMeipo().getInstance(new Customer());
                obj.findLove();
                //通过反编译工具可以查看源代码
                byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
                FileOutputStream os = new FileOutputStream("F://$Proxy0.class");
                os.write(bytes);
                os.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

      运行以上代码,在F盘下找到 $Proxy0.class 文件。使用反编译工具反编译后得到 $Oroxy.java 文件,打开看到如下内容

      

    // Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://kpdus.tripod.com/jad.html
    // Decompiler options: packimports(3) fieldsfirst ansi space 
    
    import com.xq.design.proxy.dynamicproxy.jdkproxy.Person;
    import java.lang.reflect.*;
    
    public final class $Proxy0 extends Proxy
        implements Person
    {
    
        private static Method m1;
        private static Method m3;
        private static Method m2;
        private static Method m0;
    
        public $Proxy0(InvocationHandler invocationhandler)
        {
            super(invocationhandler);
        }
    
        public final boolean equals(Object obj)
        {
            try
            {
                return ((Boolean)super.h.invoke(this, m1, new Object[] {
                    obj
                })).booleanValue();
            }
            catch (Error ) { }
            catch (Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final void findLove()
        {
            try
            {
                super.h.invoke(this, m3, null);
                return;
            }
            catch (Error ) { }
            catch (Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final String toString()
        {
            try
            {
                return (String)super.h.invoke(this, m2, null);
            }
            catch (Error ) { }
            catch (Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        public final int hashCode()
        {
            try
            {
                return ((Integer)super.h.invoke(this, m0, null)).intValue();
            }
            catch (Error ) { }
            catch (Throwable throwable)
            {
                throw new UndeclaredThrowableException(throwable);
            }
        }
    
        static 
        {
            try
            {
                m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                    Class.forName("java.lang.Object")
                });
                m3 = Class.forName("com.xq.design.proxy.dynamicproxy.jdkproxy.Person").getMethod("findLove", new Class[0]);
                m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
                m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            }
            catch (NoSuchMethodException nosuchmethodexception)
            {
                throw new NoSuchMethodError(nosuchmethodexception.getMessage());
            }
            catch (ClassNotFoundException classnotfoundexception)
            {
                throw new NoClassDefFoundError(classnotfoundexception.getMessage());
            }
        }
    }
    $Proxy0

      发现 $Proxy0 继承了Proxy 类,同时还实现了 Person 接口,而且重写了 findLove 方法。在静态块中用反射找到了目标对象的所有方法,而且保存了所有方法的引用,重写的方法用反射调用目标对象的方法。这些代码是JDK帮我们是生成的。

      我们也可以不依赖 JDK ,自己来动态生成源代码、动态完成编译,然后替代目标对象并执行。

      

    本文来自博客园,作者:l-coil,转载请注明原文链接:https://www.cnblogs.com/l-coil/p/12866294.html

  • 相关阅读:
    windows10的子系统linux(wsl)
    关于js的比较
    关于parseInt,很神奇
    vue修改数组元素通过arr[0]=val的方式不生效
    wps表格 VLookUp 函数
    青年大学习_收集截图方案
    个人记录_uwsgi,nginx与django之间的关系以及各自的作用
    Ubuntu16.04系统中创建新用户
    idea 启动或debug springboot web项目特别慢的解决方案
    利用Aop实现动态分库分表
  • 原文地址:https://www.cnblogs.com/xianquan/p/12866294.html
Copyright © 2020-2023  润新知