使用JDK API實現動態代理和源碼分析

討論和學習JDK API 實現動態代理,源碼分析

前置知識

  • 瞭解類是由屬性和方法構成
  • 瞭解Java可以動態定義類信息
  • 瞭解反射

基本概念:

動態代理:爲實現某個接口的原始類(被代理類),在運行時動態生成代理對象
代理:在被代理之前的,代理被代理的
被代理:需要代理協助的對象

邏輯推理/猜想

1.代理被代理之間要有關聯
2.對外展示的功能是一樣。
3.再想想具體的Java實現

通過什麼手段能爲一個類或者接口動態生成代理 ?

  1. 對象是由類生成,所以先需要生成類,在生成對象,
  2. 是由屬性方法構成,這裏重點關注方法,那我們我們生成的類,應該具備哪些方法呢? 因爲代理和被代理對外是一致的,所被代理有哪些方法,那代理也就有哪些方法,所以我們就可以生成類,接着就可以生成代理對象。

代碼演示

  1. 定義代理和被代理類都需要實現的接口
public interface ITest {
    void test();
}

被代理實現接口

/**
 * 被代理
 * @Author: malone
 * @Date 2020/6/26 23:08
 */
public class Represented implements ITest {
    @Override
    public void test() {
        System.out.println("Represented method invocation");
    }
}
  1. 根據JDK創建代理對象的方法需要,實現InvocationHandler接口
/**
 * @Author: malone
 * @Date 2020/6/26 23:09
 */
public class DynamicInvocationHandler implements InvocationHandler {
    // 被代理對象
    private Object object;

    public DynamicInvocationHandler(Object object){
        this.object = object;
    }
    // 方法調用攔截
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke proxy method");
        method.invoke(object,args); // 調用被代理方法,通過反射方法
        return null;
    }
}
  1. 調用public static Object newProxyInstance()創建代理對象
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

loader:當前被代理對象使用的類加載器
interfaces:需要實現接口數組
h: 第2步實現了InvocationHandler接口的對象

下面是動態代理DynamicProxy的測試,通過newProxyInstance方法,創建代理對象proxy,在代理對象上調用和被代理對象相同的方法,我們看到,代理對象和被代理對象的信息都輸出了。

/**
 * @Author: malone
 * @Date 2020/6/26 23:11
 */
public class DynamicProxyTest {

    public static void main(String[] args) {
        String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
        System.getProperties().setProperty(property ,"true");
        // 以上兩句話用於保存,JDK動態產生的代理類Proxy0
        ITest represented = new Represented();  // 被代理實例
        ITest proxy = (ITest)Proxy.newProxyInstance(represented.getClass().getClassLoader(),
                represented.getClass().getInterfaces(),new DynamicInvocationHandler(represented));
        proxy.test(); // 通過代理調用方法
    }
}

下面是輸出

invoke proxy method
Represented method invocation

源碼

  String property = "sun.misc.ProxyGenerator.saveGeneratedFiles";
  System.getProperties().setProperty(property ,"true");

上面兩個代碼將保存生成的代理類$Proxy0到本地.我,我們打開看看。

生成類所在位置
動態生成所類

public final class $Proxy0 extends Proxy implements ITest {

生成的類繼承了Proxy類,實現了ITest類,這也就保證了和被代理一致的行爲。至於繼承Proxy類是爲了調用InvocationHandler中的Invoke方法,也就是我們實現代理邏輯的方法。如下所示,我們主要看ITest中定義的方法test在生成類中的實現。

    public final void test() throws  {
        try {
        	// 調用父類Proxy中的InvocationHandler的invoke方法
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

總結

  1. 邏輯中涉及代理對象和被代理對象兩個角色
  2. 實現中,涉及接口定義、代理的定義(InvocationHandler 接口實現)、代理的創建Proxy.newProxyInstance方法的調用
  3. 涉及反射知識:被代理類的方法調用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章