JDK动态代理深刻理解分析并手写简易JDK动态代理(上)

原文同步发表至我的博客【夜月归途】html

原文连接:http://www.guitu18.com/se/java/2019-01-03/27.htmljava

本博客关于Java动态代理相关内容直达连接:ide

  1. JDK动态代理浅析
  2. Cglib动态代理浅析
  3. JDK动态代理深刻理解分析并手写简易JDK动态代理(上)
  4. JDK动态代理深刻理解分析并手写简易JDK动态代理(下)

博客真的是好几个月没更了,2019新年第一篇,继续深刻动态代理,前两篇简单分析了动态代理的实现原理以后,此次继续深刻了解具体的实现方式,并手写一套简易的动态代理已增强理解;
先接上一篇代码,这里先上代码说话,一个简单案列,代理找对象和找工做:工具

JDK动态代理只能代理有接口的类,定义Persion接口 post

package com.guitu18.study.proxy;
/**
 * @author zhangkuan
 * @email xianjian-mail@qq.com
 * @Date 2018/12/31 20:30
 */
public interface Persion {
    /**
     * 找对象
     *
     * @param condition 对另外一半的要求
     * @return 表态
     */
    String findLove(String condition);
    /**
     * 找工做
     */
    void findWord();
}

 

实现接口的类:测试

package com.guitu18.study.proxy;
/**
 * @author zhangkuan
 * @email xianjian-mail@qq.com
 * @Date 2018/12/31 20:13
 */
public class ZhangKuan implements Persion {
    @Override
    public String findLove(String condition) {
        System.out.println(condition);
        return "叶青我爱你";
    }
    @Override
    public void findWord() {
        System.out.println("我想找月薪15-25k的工做");
    }
}

 

代理类:ui

package com.guitu18.study.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @author zhangkuan
 * @email xianjian-mail@qq.com
 * @Date 2018/12/31 20:13
 */
public class JDKProxy {
    public static Object getProxyInstance(final Object target) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 方法执行前
                        System.out.println("开始事务...");
                        // 执行方法
                        Object invoke = method.invoke(target, args);
                        // 方法执行后
                        System.out.println("提交/回滚事务...");
                        return invoke;
                    }
                });
    }
}

 

代理测试类:this

package com.guitu18.study.proxy.jdk;
import com.guitu18.study.proxy.Persion;
import com.guitu18.study.proxy.ZhangKuan;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
/**
 * @author zhangkuan
 * @email xianjian-mail@qq.com
 * @Date 2018/12/31 20:28
 */
public class JDKProxyTest {
    public static void main(String[] args) {
        try {
            Persion persion = (Persion) JDKProxy.getProxyInstance(new ZhangKuan());
            String love = persion.findLove("肤白貌美大长腿");
            System.out.println(love); // 叶青我爱你
            System.out.println(persion.getClass()); // class com.sun.proxy.$Proxy0
            /**
             * 上面生成的代理对象字节码 com.sun.proxy.$Proxy0 是在内存中的
             * 这里将其对象写到文件中,经过反编译查看
             */
            byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Persion.class});
            FileOutputStream fos = new FileOutputStream("D://$Proxy0.class");
            fos.write(bytes);
            System.out.println("文件写入成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

到这里,代理任务已经能够完成看;此处,咱们将JDK动态代理生成的代理类,经过流的形式保存到磁盘中了,如今使用idea自带反编译工具查看:url

import com.guitu18.study.proxy.Persion;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Persion {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    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 findWord() 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 findLove(String var1) throws  {
        try {
            return (String)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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.guitu18.study.proxy.Persion").getMethod("findWord");
            m3 = Class.forName("com.guitu18.study.proxy.Persion").getMethod("findLove", 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());
        }
    }
}

 

看完这段代码是否是恍然大悟的感受,生成的代理类继承了Proxy类并实现了咱们的接口,并生成了被代理类的所有方法,包括toString、equals等等全部方法; 这里生成的代理类继承自Proxy,在Proxy中有这么一段代码:idea

/**
 * the invocation handler for this proxy instance.
 * @serial
 */
protected InvocationHandler h;

 

这就是为何咱们在生成代理类的时候,要传入的一个InvocationHandler的实现,咱们全部的代理加强代码都写在invoke()方法中,而最终代理类执行代理也是经过调用父类Proxy中的InvocationHandler接口的invoke()方法;
而咱们知道Java是单继承的,因此代理类只能去实现咱们的接口以供咱们能够将其强转;
在咱们调用自身方法时,代理类巧妙的经过调用生成的同名方法而后调用super.h.invoke()方法,最终就到了咱们实现InvocationHandler时所写的invoke()加强方法;在此时,method.invoke()才真正经过反射调用了咱们自身所写的方法;这种极为巧妙无侵入式的方法加强实在是妙,使人叹为观止;

这里推荐一篇 劳夫子 的 [ ProxyGenerator生成代理类的字节码文件解析 ];
分析的是ProxyGenerator.generateClassFile()字节码生成原理,写的很是好,值得好好看一下;

下一篇,经过手写一套简易的JDK动态代理的实现加强理解;

相关文章
相关标签/搜索