通過反編譯後的字節碼理解jdk代理

一:使用例子


public class ProxyDemo implements InvocationHandler {

    static ProxyDemo proxyDemo = new ProxyDemo();

    public ProxyDemo() {
    }

    private Object sub;

    public ProxyDemo(Object obj) {
        sub = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("被調用代理對象的方法: " + method.getName() + ":" + method.getDeclaringClass());
        System.out.println("before method !!!!!");
        Object invoke = method.invoke(sub, args);
        System.out.println("after method !!!!!");
        return invoke;
    }

    public <T> T getProxy(T t) {
        ProxyDemo handler = new ProxyDemo(t);
        return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), handler);
    }


    public static void main(String[] args) {
        PersonDao pDao = new PersonDaoImpl();
        PersonDao proxy = proxyDemo.getProxy(pDao);
        proxy.say();
        System.out.println("完成");
       
    }

}

interface PersonDao {
    void say();
}

class PersonDaoImpl implements PersonDao {

    @Override
    public void say() {
        System.out.println("hello boy");
    }

}

二:代碼流程跟蹤,找到使用接口的位置

三:最終通過ProxyGenrator的generateProxyClass方法,使用接口Class生成代理的byte[],保存字節碼信息到class文件,idea打開並查看文件


    public static void main(String[] args) {
        Class<?>[] interfaces = new Class[]{PersonDao.class};
        // 獲取代理字節碼文件,
        byte[] bytes = ProxyGenerator.generateProxyClass("PersonDao", interfaces);
        File file = new File("./jdk/src/main/java/javaDemo/proxyDemo/PersonDao.class");
        try {
            OutputStream outputStream = new FileOutputStream(file);
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

PersonDao.class文件,可以看到代理類繼承了Proxy,調用sya方法會執行super.h.invoke,並實現了傳入的接口,因爲所有生成的代理類的父類爲Proxy,Java類繼承機制不允許多重繼承,所以被代理類必須實現接口。並且實驗的過程證明了可以對final的方法和類進行代理,知道滿足接口實現即可。

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

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import javaDemo.proxyDemo.PersonDao;

public final class PersonDao$Proxy extends Proxy implements PersonDao {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public PersonDao$Proxy(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 say() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("javaDemo.proxyDemo.PersonDao").getMethod("say");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章