源碼閱讀JDK動態代理實現

上次更新了一篇設計模式之代理模式,今天仔細的瞭解了一下JDK實現的原理,又看了一下網上其實不少人都說本身也能實現一個代理模式,手癢就敲了一下。 想要學習完整代理模式的能夠看我前幾篇更新的文章: www.jianshu.com/p/bee8a547f…java

動態代理主要有兩種,一種是JDk提供的,代理類須要實現InvocationHandle接口,而後內部在構造方法去返回一個Proxy生成的代理類實例,而後還要從新invoke這個方法,在這個方法中實現代理類想要作的事。設計模式

在客戶端獲取這個代理類以後,直接調用方法就能夠了。 另一種就是經過CGLib實現的。這個我下次再來研究,此次是實現的JDK的動態代理模式。ide

能夠先來貼一段代碼(按註釋編號讀):函數

//1.這是一個被代理類
public class XieMu implements Person {

    @Override
    public void findLove(){
        System.out.println("高富帥");
        System.out.println("身高180cm");
        System.out.println("胸大,6塊腹肌");
    }

    @Override
    public void zufangzi() {
        System.out.println("租房子");
    }

    @Override
    public void buy() {
        System.out.println("買東西");
    }

    @Override
    public void findJob() {
        System.out.println("月薪20K-50k");
        System.out.println("找工做");
    }
}

// 2.這是一個媒婆的代理類
public class JDKMeipo implements InvocationHandler{
    //被代理的對象,把引用給保存下來
    private Person target;

    public Object getInstance(Person target) throws Exception{
        this.target = target;

       Class<?> clazz = target.getClass();

        //下半截,深刻底層來給你們講解字節碼是如何重組的
        //用來生成一個新的對象(字節碼重組來實現)
        /** * JDK提供了一個Proxy.newProxyInstance(代理類的類加載器,代理類實現的接口,代理類自己)咱們直接調用,他就會幫咱們在運行時動態生成一個代理類。 */
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);

//他的客戶端實現以下:
//3能夠看到,經過媒婆這個類返回了一個代理類,這個類跟被代理類實現了一樣的接口Person,返回Person
Person obj = (Person)new JDKMeipo().getInstance(new XieMu());
            System.out.println(obj.getClass());
            obj.findJob();
    }

複製代碼

能夠看到,客戶端只須要經過這個媒婆類的getInstance,就能夠返回一個咱們被代理類實現的接口的代理類。而後咱們深刻Proxy.newProxyInstance來看一下:工具

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
        Objects.requireNonNull(h);
        //淺複製了被代理類實現的接口
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
          //檢查建立Proxy類所需的權限
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /* * 查找或生成制定的代理類 */
        Class<?> cl = getProxyClass0(loader, intfs);

        /* *使用指定的調用處理程序調用其構造函數 */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
//重點來了,反射獲取constructorParams,也就是InvocationHandler.class類的構造器
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;  //看了上下文,發現沒意義。
            //獲取此類cl,即代理類的java語言修飾符,判斷若是不是public的訪問域,則設置能夠setAccessible(true);訪問
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
//以上的設置,是爲了下面代理類的構造器新生成一個代理類實例,經過反射去生成
            return cons.newInstance(new Object[]{h});
複製代碼

而後接這cons.newInstance(new Object[]{h});繼續看: 能夠經過雙親委派模式,去判斷,最終是這裏實現了新建一個對象。學習

return UnsafeFieldAccessorImpl.unsafe.allocateInstance(this.constructor.getDeclaringClass());
複製代碼

而後來看,那麼咱們實現InvocationHandle,從新invoke跟這個Proxy有什麼關聯呢? 再來看一下。Proxy類有一個這樣的註釋:ui

An interface method invocation on a proxy instance will be
 * encoded and dispatched to the invocation handler's {@link
 * InvocationHandler#invoke invoke} method as described in the
 * documentation for that method
代理實例上的接口方法調用將被編碼並調度到調用處理程序的{@link * InvocationHandler#invoke invoke}方法,如該方法的*文檔中所述
複製代碼

最後咱們再來看一下,經過Proxy生成的代理類打印出來是什麼?this

class com.sun.proxy.$Proxy0  //JDK中有個規範,只要要是$開頭的通常都是自動生成的,因此確定是Proxy自動生成一個代理類後,再加載到JVM去運行的。

 //經過反編譯工具能夠查看源代碼
            byte [] bytes = ProxyGenerator.generateProxyClass("$Proxy0",new Class[]{Person.class});
            FileOutputStream os = new FileOutputStream("E://$Proxy0.class");
            os.write(bytes);
            os.close();

查看到的代碼以下:
import com.zxy.test.gupao.tom.proxy.staticed.Person;
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 Person {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m6;
    private static Method m4;
    private static Method m5;
    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 void findLove() throws  {
        try {
            super.h.invoke(this, m3, (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 zufangzi() throws  {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

    public final void findJob() throws  {
        try {
            super.h.invoke(this, m5, (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"));
            m3 = Class.forName("com.zxy.test.gupao.tom.proxy.staticed.Person").getMethod("findLove");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m6 = Class.forName("com.zxy.test.gupao.tom.proxy.staticed.Person").getMethod("zufangzi");
            m4 = Class.forName("com.zxy.test.gupao.tom.proxy.staticed.Person").getMethod("buy");
            m5 = Class.forName("com.zxy.test.gupao.tom.proxy.staticed.Person").getMethod("findJob");
            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底層實現JDK的原理:編碼

//原理:
            //一、拿到被代理對象的引用,而且獲取到它的全部的接口,反射獲取
            //二、JDK Proxy類從新生成一個新的類、同時新的類要實現被代理類全部實現的全部的接口
            //三、動態生成Java代碼,把新加的業務邏輯方法由必定的邏輯代碼去調用(在代碼中體現)
            
            //四、編譯新生成的Java代碼.class
            //五、再從新加載到JVM中運行
            //以上這個過程就叫字節碼重組
複製代碼

好了,以上我已經總結了JDK底層是如何實現動態代理的了,那麼下面我將本身來實現JDK動態代理。 能夠看個人下一篇博客哦: 地址: www.jianshu.com/p/9608c628f…spa

相關文章
相關標籤/搜索