jdk動態(tài)代理-生成的代理類的字節(jié)碼

被代理的類

package com.example.demo.jdkproxytest;

/**
 * Created by PengRong on 2018/12/25.
 * 創(chuàng)建Person 接口 用于定義 委托類和代理類之間的約束行為
 */
public interface Person {
    /**
     * @param name 人名
     * @param dst  工作目的地
     */
    void goWorking(String name, String dst);

    /**
     * 獲取名稱
     *
     * @return
     */
    String getName();

    /**
     * 設(shè)置名稱
     *
     * @param name
     */
    void setName(String name);
}

接口實現(xiàn)類崎脉, 被代理類

package com.example.demo.jdkproxytest;

/**
 * Created by PengRong on 2018/12/25.
 * 動態(tài)代理委托類實現(xiàn)蹦漠, 實現(xiàn)接口 Person典唇。 被動態(tài)生成的代理類代理
 */
public class SoftwareEngineer implements Person {

    private String name;


    public SoftwareEngineer() {
    }

    public SoftwareEngineer(String name) {
        this.name = name;
    }


    @Override
    public void goWorking(String name, String dst) {
        System.out.println("name =" + name + " 犹褒, 去 " + dst + " 工作");
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}


InvocationHandler

package com.example.demo.jdkproxytest;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * Created by PengRong on 2018/12/25.
 * PersonInvocationHandler 類 實現(xiàn)InvocationHandler接口,這個類中持有一個被代理對象(委托類)的實例target。該類別JDK Proxy類回調(diào)
 * InvocationHandler 接口中有一個invoke方法逮壁,當一個代理實例的方法被調(diào)用時凌盯,代理方法將被編碼并分發(fā)到 InvocationHandler接口的invoke方法執(zhí)行。
 */
public class PersonInvocationHandler<T> implements InvocationHandler {
    /**
     * 被代理對象引用掐隐,invoke 方法里面method 需要使用這個 被代理對象
     */
    T target;

    public PersonInvocationHandler(T target) {
        this.target = target;
    }

    /**
     * 在
     *
     * @param proxy  代表動態(tài)生成的 動態(tài)代理 對象實例
     * @param method 代表被調(diào)用委托類的接口方法狗热,和生成的代理類實例調(diào)用的接口方法是一致的,它對應(yīng)的Method 實例
     * @param args   代表調(diào)用接口方法對應(yīng)的Object參數(shù)數(shù)組虑省,如果接口是無參匿刮,則為null; 對于原始數(shù)據(jù)類型返回的他的包裝類型探颈。
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        /**
     * 在轉(zhuǎn)調(diào)具體目標對象之前熟丸,可以執(zhí)行一些功能處理
     */
        System.out.println("被動態(tài)代理類回調(diào)執(zhí)行, 代理類 proxyClass =" + proxy.getClass() + " 方法名: " + method.getName() + "方法. 方法返回類型:" + method.getReturnType()
                + " 接口方法入?yún)?shù)組: " + (args == null ? "null" : Arrays.toString(args)));        /**
         * 代理過程中插入監(jiān)測方法,計算該方法耗時
         */
        MonitorUtil.start();
        Thread.sleep(1);        /** 調(diào)用唄代理對象的真實方法,*/
        Object result = method.invoke(target, args);
        MonitorUtil.finish(method.getName());
        return result;
    }
}

MonitorUtil


package com.example.demo.jdkproxytest;

/**
 * Created by PengRong on 2018/12/25.
 * 方法用時監(jiān)控類
 */
public class MonitorUtil {
    private static ThreadLocal<Long> tl = new ThreadLocal<>();

    public static void start() {
        tl.set(System.currentTimeMillis());
    }

    /**
     * 結(jié)束時打印耗時
     *
     * @param methodName 方法名
     */
    public static void finish(String methodName) {
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName + "方法執(zhí)行耗時" + (finishTime - tl.get()) + "ms");
    }
}


測試類

package com.example.demo.jdkproxytest;


import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Properties;

/**
 * 動態(tài)代理類測試
 * Created by PengRong on 2018/12/25.
 */
public class JdkDynamicProxyTest {
    public static void main(String[] args) throws Exception {
        // 打開保存JDK動態(tài)代理生成的類文件
        saveGeneratedJdkProxyFiles();

        /**
         * 第一種方法: 通過 Proxy.newProxyInstance 方法 獲取代理對象
         */
        System.out.println("-------------------第一種創(chuàng)建代理類方法--------------");

        //創(chuàng)建一個實例對象伪节,這個對象是被代理的對象光羞,委托類
        Person person = new SoftwareEngineer("Vincent");

        //創(chuàng)建一個與代理類相關(guān)聯(lián)的InvocationHandler,每一個代理類都有一個關(guān)聯(lián)的 InvocationHandler,并將代理類引用傳遞進去
        InvocationHandler Handler = new PersonInvocationHandler<>(person);

        //創(chuàng)建一個 代理對象 personProxy 來代理 person怀大,創(chuàng)建的代理對象的每個執(zhí)行方法都會被替換執(zhí)行Invocation接口中的invoke方法
        Person personProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, Handler);

        /** 代理類信息 */
        System.out.println("package = " + personProxy.getClass().getPackage() + " SimpleName = " + personProxy.getClass().getSimpleName() + " name =" + personProxy.getClass().getName() + " CanonicalName = " + "" + personProxy.getClass().getCanonicalName() + " 實現(xiàn)的接口 Interfaces = " + Arrays.toString(personProxy.getClass().getInterfaces()) + " superClass = " + personProxy.getClass().getSuperclass() + " methods =" + Arrays.toString(personProxy.getClass().getMethods()));        // 通過 代理類 執(zhí)行 委托類的代碼邏輯
        personProxy.goWorking(personProxy.getName(), "深圳");


        System.out.println("-------------------第二種創(chuàng)建代理類方法--------------");

        /**
         *  動態(tài)代理對象步驟
         *      1纱兑、 創(chuàng)建一個與代理對象相關(guān)聯(lián)的 InvocationHandler,以及真實的委托類實例
         *      2化借、Proxy類的getProxyClass靜態(tài)方法生成一個動態(tài)代理類stuProxyClass潜慎,該類繼承Proxy類,實現(xiàn) Person.java接口;JDK動態(tài)代理的特點是代理類必須繼承Proxy類
         *      3勘纯、通過代理類 proxyClass 獲得他的帶InvocationHandler 接口的構(gòu)造函數(shù) ProxyConstructor
         *      4局服、通過 構(gòu)造函數(shù)實例 ProxyConstructor 實例化一個代理對象,并將  InvocationHandler 接口實例傳遞給代理類驳遵。
         */
//        // 1淫奔、創(chuàng)建 InvocationHandler 實例并設(shè)置代理的目標類對象
//        Person persontwo = new SoftwareEngineer("Vincent");
//        InvocationHandler Handlertwo = new PersonInvocationHandler<>(persontwo);
//
//        // 2 創(chuàng)建代理類,是一個字節(jié)碼文件, 把 proxyClass 保存起來就能看到 他繼承Proxy 類,實現(xiàn)Person接口
//        Class<?> proxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
//
//        /** 代理類信息 */
//        System.out.println("package = " + proxyClass.getPackage() + " SimpleName = " + proxyClass.getSimpleName() + " name =" + proxyClass.getName() + " CanonicalName = " + "" + proxyClass.getCanonicalName() + " 實現(xiàn)的接口 Interfaces = " + Arrays.toString(proxyClass.getInterfaces()) + " superClass = " + proxyClass.getSuperclass() + " methods =" + Arrays.toString(proxyClass.getMethods()));        // 3堤结、  通過 proxyClass 獲得 一個帶有InvocationHandler參數(shù)的構(gòu)造器constructor
//        Constructor<?> ProxyConstructor = proxyClass.getConstructor(InvocationHandler.class);
//
//        // 4唆迁、通過構(gòu)造器創(chuàng)建一個  動態(tài)代理類 實例
//        Person stuProxy = (Person) ProxyConstructor.newInstance(Handlertwo);
//
//        /** 檢測生成的類是否是代理類 */
//        System.out.println("stuProxy isProxy " + Proxy.isProxyClass(stuProxy.getClass()));
//
//        /** 獲取 代理類關(guān)聯(lián)的 InvocationHandler 是哪個*/
//        InvocationHandler handlerObject = Proxy.getInvocationHandler(stuProxy);
//        System.out.println(handlerObject.getClass().getName());
//        stuProxy.goWorking(stuProxy.getName(), "廣州");
//
//        // 保存代理類
//        String pathdir = "/Users/benjamin/IntelliJIdeaProjects/springboot-mydemo/demo/jdkdynamicclasses";
//        saveClass("$PersonProxy0", proxyClass.getInterfaces(), pathdir);
    }

    /**
     * 生成代理類 class 并保持到文件中
     *
     * @param className  生成的代理類名稱
     * @param interfaces 代理類需要實現(xiàn)的接口
     * @param pathdir    代理類保存的目錄路徑,以目錄分隔符結(jié)尾
     */
    public static void saveClass(String className, Class<?>[] interfaces, String pathdir) {        /**
     * 第一個參數(shù)是 代理類 名 。
     * 第二個參數(shù)是 代理類需要實現(xiàn)的接口
     */
        byte[] classFile = ProxyGenerator.generateProxyClass(className, interfaces);

        /**
         * 如果目錄不存在就新建所有子目錄
         */
        Path path1 = Paths.get(pathdir);
        if (!path1.toFile().exists()) {
            path1.toFile().mkdirs();
        }

        String path = pathdir + className + ".class";
        try (FileOutputStream fos = new FileOutputStream(path)) {
            fos.write(classFile);
            fos.flush();
            System.out.println("代理類class文件寫入成功");
        } catch (Exception e) {
            System.out.println("寫文件錯誤");
        }
    }

    /**
     * 設(shè)置保存Java動態(tài)代理生成的類文件竞穷。
     *
     * @throws Exception
     */
    public static void saveGeneratedJdkProxyFiles() throws Exception {
        Field field = System.class.getDeclaredField("props");
        field.setAccessible(true);
        Properties props = (Properties) field.get(null);
        props.put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    }
}

生成的代理類的字節(jié)碼

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.example.demo.jdkproxytest.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 m4;
    private static Method m3;
    private static Method m2;
    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 setName(String var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String getName() throws  {
        try {
            return (String)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 goWorking(String var1, String var2) throws  {
        try {
            super.h.invoke(this, m5, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    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.example.demo.jdkproxytest.Person").getMethod("setName", Class.forName("java.lang.String"));
            m3 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("getName");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m5 = Class.forName("com.example.demo.jdkproxytest.Person").getMethod("goWorking", Class.forName("java.lang.String"), 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());
        }
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唐责,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瘾带,更是在濱河造成了極大的恐慌鼠哥,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件看政,死亡現(xiàn)場離奇詭異朴恳,居然都是意外死亡,警方通過查閱死者的電腦和手機允蚣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門于颖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人嚷兔,你說我怎么就攤上這事森渐。” “怎么了冒晰?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵同衣,是天一觀的道長。 經(jīng)常有香客問我翩剪,道長乳怎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任前弯,我火速辦了婚禮蚪缀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恕出。我一直安慰自己询枚,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布浙巫。 她就那樣靜靜地躺著金蜀,像睡著了一般刷后。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渊抄,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天尝胆,我揣著相機與錄音,去河邊找鬼护桦。 笑死含衔,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的二庵。 我是一名探鬼主播贪染,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼催享!你這毒婦竟也來了杭隙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤因妙,失蹤者是張志新(化名)和其女友劉穎痰憎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攀涵,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡信殊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了汁果。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡玲躯,死狀恐怖据德,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跷车,我是刑警寧澤棘利,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站朽缴,受9級特大地震影響善玫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜密强,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一茅郎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧或渤,春花似錦系冗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惯豆。三九已至,卻和暖如春奔害,著一層夾襖步出監(jiān)牢的瞬間楷兽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工华临, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留芯杀,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓银舱,卻偏偏與公主長得像瘪匿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寻馏,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348