Proxy代理對象是如何調用invoke()方法的.


直奔主題,不說廢話.先看java使用Proxy創建代理對象的代碼.

//一個開發者接口
public
interface Developer { String code(); void debug(); }

 

//一個具體的開發者,實現兩個接口
public
class JavaDeveloper implements Developer { private String name; public JavaDeveloper(String name) { this.name = name; } @Override public String code() { System.out.println(name + "寫代碼"); return "寫好了"; } @Override public void debug() { System.out.println(name + "調試bug"); } }
public class JavaDynamicProxy {
    public static void main(String[] args) {
        /*這個根據情況自行輸入,主要功能是將生成出的代理對象Class文件存到本地.
        我用的idea編輯器,最終生成的文件在 工作空間下的 com\sun\proxy 文件夾中*/
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        //具體類,需要增強的類
        JavaDeveloper zack = new JavaDeveloper("Zack");
        /*Proxy.newProxyInstance 方法三個參數
         * 1 一個類加載器
         * 2 需要增強的類都實現了哪些接口,或哪些父類.這個很重要,因為最終生成的代理類,是要重寫父類的方法的.
         * 3 一個調用處理器.是一個接口,需要實現接口中的方法,就一個invoke().這個方法很重要,你使用代理對象中的方法,
         * 每次都會經過這個方法.這也就是增強的核心.invoke()的三個參數
         *   1 需要增強原始對象.這里需要指定一個原型方法.
         *   2 即將執行的增強方法,這個Method 當你調用代理對象的A方法,這個Method就是A方法的Class對象.
         *   3 方法參數.A方法的參數. 熟悉反射的朋友應該能理解,一個Method方法執行,需要一個實例對象,和方法參數列表.
         * */

        Developer zackProxy = (Developer) Proxy.newProxyInstance(zack.getClass().getClassLoader(),
                zack.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        /* 我這里分別對兩個方法進行了不同的增強.需要注意的是 返回值
                         *  如果你的方法沒有返回值可以 return null*/
                        if (method.getName().equals("code")) {
                            System.out.println("正在祈禱.....");
                            method.invoke(zack, args);
                            return "動態的寫好了";
                        }
                        if (method.getName().equals("debug")) {
                            System.out.println("已經祈禱了,怎么還有bug");
                            method.invoke(zack, args);
                        }
                        return null;
                    }
                });
        //使用代理對象
        String s = zackProxy.code();
        zackProxy.debug();
        System.out.println(s);

      /*打印結果
        正在祈禱.....
        Zack寫代碼
        已經祈禱了,怎么還有bug
        Zack調試bug
        動態的寫好了*/
    }
}

我這里不關注代理對象的生成.有興趣的可以自行查看.下邊是生成代理對象的Class源文件,經過反編譯后.


/*注意 當前反編譯文件其中還有hashCode()toString()equals(Object obj)三個Object的方法.
這三個方法都是Object中可以被覆蓋的方法.這也就是Proxy.newProxyInstance()方法第二個參數
的作用.*/
public final class $Proxy0 extends Proxy
implements Developer {


  //這里我把object的方法去掉了.直奔主題
private static Method m3;//debug 自定義的方法
private static Method m4;//code 自定義的方法


static {
try {
//初始化了兩個Method,通過類名創建Class對象,在通過方法名獲取Method對象.
m3 = Class.forName("sis.proxytest.Developer").getMethod("debug", new Class[0]);
m4 = Class.forName("sis.proxytest.Developer").getMethod("code", new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}

public $Proxy0(InvocationHandler invocationhandler) {
// 這里我把父類也就是 Proxy 部分代碼貼上.
// protected InvocationHandler h;//父類成員變量
// protected Proxy(InvocationHandler h) {//父類構造子
// Objects.requireNonNull(h);
// //就是把我們new出來的 InvocationHandler傳遞給了父類
// this.h = h;
// }
super(invocationhandler);
}

//這才是重點
public final void debug() {
try {
/* 當我們使用代理對象調用 debug()方法時.會使用父類Proxy的h成員變量的invoke()
這個h就是我們開篇使用Proxy.newProxyInstance創建代理對象中的第三個參數*/
super.h.invoke(this, m3, null);
return;
} catch (Error) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

public final String code() {
try {
return (String) super.h.invoke(this, m4, null);
} catch (Error) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}

以上就是Proxy生成代理對象,是如果使用invoke()方法的過程.如有不足請補充.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM