Proxy 代理模式 | 解說實現 | 分析動態代理

Proxy 代理模式 | 解說實現 | 分析動態代理

Overview of Content

如有引用參考請詳註出處,感謝

在這篇文章中,我們將深入探討 代理模式(Proxy Pattern的實現與解說,特別關注動態代理的分析。

首先,我們會提供整體內容的概述,並深入了解代理模式的概念。接著,我們將解釋代理模式的定義,並透過UML結構呈現其模型。在設計方面,我們會詳細討論代理模式的優缺點,使讀者能全面了解其應用範疇。

在實際實做部分,我們將深入探討代理模式的兩種基本實現方式,分別是普通代理強制代理

隨後,我們轉向動態代理,介紹 InvocationHandler 介面以及動態代理的 UML 結構。透過實際程式碼,我們將展示動態代理的兩種實現方式,包括實體類和匿名類。最後,我們將解析 Proxy 生成的動態代理類,深入分析其結構,包括 IO 輸出 Proxy 類以及對動態代理的進一步分析。透過這篇文章,讀者將深入理解代理模式的實際應用,尤其是動態代理的原理與實現。


Proxy 概述

代理可做到加強源類,也可隔離,JDK 有提供接口,並且代理類分為兩種 1. 靜態代理、2. 動態代理

動態代理使會用到 Java 反射,動態代理使用的地方也很多,像是 Android Retrofit 就有使用到,一般我們在 Hook 資料時也常使用到

Proxy 定義 & Proxy UML

● Proxy 定義:為其他物件提供代理來訪問目標物件

● Proxy UML、角色關係

關係
Subject (抽象、接口)定義一個對外的抽象方法
RealSubject實際實現業務者
Proxy代理 RealSubject 對象,內部持有一個 Subject 對象,將所有實做委託給真實對象(RealSubject)

Proxy 設計:優缺點

A. Proxy 設計 靜態代理

● 優點:Proxy 的類建構、連接於編譯期間,所以運行速度較快

● 缺點:不符合開閉原則,維護代價較高,會為了增加功能而不斷新增修改代理類

● 當代理類(Proxy)需要代理多個不同接口時就必須修改,維護成本會提高

B. Proxy 設計 動態代理:使用反射需要時才創建

● 優點:透過 JDK 自動生成代碼,在運行時加強代碼

● 缺點:Proxy 類建構、連接於運行期間,所以速度較慢

Proxy 實現

Proxy 普通代理

普通代理的意思:使用者不必知道真實類是誰,而是透過代理類來訪問對象(這符合迪米特原則,不用讓外部了解代理的相關類)

以下範例,代理書本購買

A. Subject 抽象:AlienShop 定義對外暴露的方法


interface AlienShop {
    fun buyBook(name: String)

    fun getBook(): String
}

B. RealSubject:RealShop 實做購買書籍的邏輯


class RealShop : AlienShop {

    override fun buyBook(name: String) {
        println("$name book the Book")
    }

    override fun getBook(): String {
        return "平行世界"
    }

}

C. Proxy:在代理類中可以加強原來的方法,但是到實際要執行時,仍是執行 RealSubject 的方法


class ProxyShop : AlienShop {

    private val realShop = RealShop() // 可在內部自己創建

    override fun buyBook(name: String) {
        println("-----Proxy help $name buy Book") // 代理加強
        realShop.buyBook(name)
    }

    override fun getBook(): String {
        println("-----Proxy help get Book ") // 代理加強
        return realShop.getBook()
    }

}

● User 使用代理設計


fun main() {

    val shop : AlienShop = ProxyShop().also {
        it.buyBook("Kyle")

        println(it.getBook())
    }

}

Proxy 強制代理

強制代理:強制代理是代理設計中比較特別的概念,作為強制代理設計的使用者,你 可以直接接觸到實做類,你可以選擇是否直接訪問該類的方法,或是透過該類指定的代理類你才能代理

A. Subject 抽象:該抽象重點是增加了一個 getProxy 方法,返回了一個 Subject 抽象,這個方法就是強制代理的重點之一

當然,如果想想要實作「強制的特性」,那就不要對外暴露可操作的方法介面,可以透過 介面隔離原則 來區分內外介面


interface IPlayGame {

    fun play()

    fun getProxy() : IPlayGame

}

B. RealSubject:實做 IPlayGame 接口,對於 getProxy 則定義一個指定的代理類!


class AlienPlay : IPlayGame {

    private var proxy : IPlayGame? = null

    override fun play() {
        proxy.let { 
            if (it == null) {   // it 是 kotlin 的語法糖提供,它表的也是呼叫者(也就是 proxy)
                println("Call proxy to play")
                return    // 在這邊你甚至可以做拋出 Exception 的行為!強制使用者一定要用代理
            }

            println("Playing game now ~")
        }
    }

    override fun getProxy(): IPlayGame {
        // 創建指定代理類
        proxy = AppleProxyPlay(this)

        return proxy!!
    }

}

C. Proxy:代理類同樣使用 RealSubject 的實做;這裡的 getProxy 則返回自身

當然這裡的代理類還是可以返回其他的代理,不一定要返回 this


class AppleProxyPlay constructor(private val real: IPlayGame) : IPlayGame {
    override fun play() {
        println("Proxy start play")
        real.play()
        println("Proxy finish play")
    }

    override fun getProxy(): IPlayGame {
        return this
    }

}

● User 使用強制代理


fun main() {

    AlienPlay().run {
        // 沒透過代理類不能訪問
        play()
        
        // 必須透過代理類才能訪問!
        getProxy().play()
    }

}


Java 動態代理

動態代理與靜態代理最大的差別在於,動態代理載運行時才指定代理對象(指定代理接口)

動態代理內部原理

Java 動態代理在源碼中是使用了 反射的技巧

應用場景侷限

由於 Java Proxy 類是 class 並非 interface,而 Java 是單繼承 (每個代理類都繼承了 Proxy 類,等等可以看到),即 只能對介面創建代理,不對類創建代理類

InvocationHandler 介面 & 動態代理 UML

InvocationHandler 是一個介面(接口),它的功能相當於一個 Hook Callback,在調用真正方法前會先調遇到這個方法 (分析碼可以看見),代理類一定要實現這個介面(接口)

動態代理 UML

動態代理透過自動生成的 Proxy 類,並使用生成的 Proxy 類來訪問真正時做類 (概念如同靜態,但它的彈性較大,許多框架都會使用到這個設計概念)

動態代理:實體類

● 直接看動態代理的範例


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class mainClass {
    
    public static void main(String []args) {
        // 創建真實實做類
        Shop book = new RealBookShop();
        CommonProxyShop commonProxyShop = new CommonProxyShop();    // 創建代理類
        commonProxyShop.setShop(book);    // 設定代理類
        // 取得代理類
        BookShop s1 = (BookShop) commonProxyShop.getProxy();
        System.out.println(s1.getBook());

        // 創建真實實做類
        Shop tool = new RealToolShop();
        CommonProxyShop commonProxyShop2 = new CommonProxyShop();    // 創建代理類
        commonProxyShop2.setShop(tool);    
        
        // 取得代理類
        ToolShop t1 = (ToolShop) commonProxyShop2.getProxy();
        System.out.println(t1.getTool());
    }
}

// 代理類
class CommonProxyShop implements InvocationHandler {
    private Object object;

    void setShop(Shop object) {
        this.object = object;
    }

    // 獲取代理類 Proxy
    Proxy getProxy() {
        return (Proxy) Proxy.newProxyInstance(
            object.getClass().getClassLoader(),    // 類加載器
            object.getClass().getInterfaces(),     // 該類所有接口
            this);    // InvocationHandler 實現
    }

    // 動態創建的 Proxy 類會呼叫此接口 (InvocationHandler)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("CommonProxyShop ask shop");
        // 第一個參數,是真正要被執行的類
        Object o = method.invoke(object, args);
        System.out.println("Shop reply CommonProxyShop");
        return o;
    }
}

// 創建一個接口,在自動生成的 Proxy 類中,會繼承該類
interface Shop { }

interface BookShop extends Shop {
    String getBook();
}

// 真實實做類
class RealBookShop implements BookShop{
    @Override
    public String getBook() {
        return null;
    }
}

interface ToolShop extends Shop {
    String getTool();
}

class RealToolShop implements ToolShop{
    @Override
    public String getTool() {
        return null;
    }

--實做--

動態代理:匿名類

● 其實跟上面的是相同的,只是把 InvocationHandler 改為匿名類 (順便多了個範例)

注意反射時帶入的物件要帶入 目標代理對象,不要寫成代理自身


public class dynamicProxy {

    public static void  main(String[] str) {

        final Pan pan = new Pan();    // 被代理者

        /*  Java 自己生成代理類
         *  引數
         *  1. 被代理者的類加載器
         *  2. 代理 interface
         *  3. 注入接口 InvocationHandler (Hook interface)
         */
        Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
                // 不可代理類 String.class! 因為生成的類繼承 Proxy
                // 而 Java 是單繼承,這也就是為何只能實現接口代理
                // 下面會介紹
                new Class[]{Hello.class, World.class},  
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        System.out.println("----------------get Invoke-------------------");
                        System.out.println("Method Name: " + method.getName());
                        // 這個 o 是 Proxy,不能自己代理自己 !! 否則會造成遞迴
                        //return method.invoke(o, objects);         

                        // invoke 要被代理的物件 (也就是真正實作類 pan)
                        return method.invoke(pan, objects);   
                    }
                }
        );

        Hello hello = (Hello) o;
        hello.talk("Hello");

        World world = (World) o;
        System.out.println(world.say());
    }
}

// 真正實作類
class Pan implements Hello, World{
    @Override
    public void talk(String s) {
        System.out.println("talk: " + s);
    }

    @Override
    public String say() {
        return "World";
    }
}

interface Hello {
    void talk(String s);
}

interface World {
    String say();
}

--實作--


解析 Proxy 生成動態代理類

IO 輸出 Proxy 類

● 在這裡我們要查看自動生成的程式,會使用到 IO 流輸出檔案 (將自動生成的程式輸出,這樣我們才可以看到~ )

代理內找到的方法可以做用在不同的 class 實例中 (該 class 必須要此方法)

Function功能
ProxyGenerator.generateProxyClass自動在 內存 產生代理類

// 動態代理範例

public class dynamicProxy {

    public static void  main(String[] str) {

        final Pan pan = new Pan();    // 被代理者
        /*  Java 自己生成代理類
         *  引數
         *  1. 類加載器
         *  2. 代理 interface
         *  3. 注入接口 InvocationHandler
         */
        Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
                new Class[]{Hello.class, World.class},  // 不可代理類 String.class! 因為生成的類繼承 Proxy
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        System.out.println("----------------get Invoke-------------------");
                        System.out.println("Method Name: " + method.getName());
                        //return method.invoke(o, objects);         // 不能自己代理自己
                        return method.invoke(pan, objects);
                    }
                }
        );

        // 使用代理 o,來呼叫到 Hello interface
        Hello hello = (Hello) o;
        hello.talk("Hello");

        World world = (World) o;
        System.out.println(world.say());

        // 使用 IO 輸出自動生成的程式
        try {
            proxy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void proxy() throws Exception {
        // 產生的 Class name
        String name = "$Proxy0";
        byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Hello.class, World.class});
        
        // IO 輸出的檔案名稱
        FileOutputStream fos = new FileOutputStream("ProcessSource/" + name + ".class");
        fos.write(bytes);
        fos.close();
    }
}

class Pan implements Hello, World{
    @Override
    public void talk(String s) {
        System.out.println("talk: " + s);
    }

    @Override
    public String say() {
        return "World";
    }
}

interface Hello {
    void talk(String s);
}

interface World {
    String say();

透過 ProxyGenerator#generateProxyClass 生成的程式

// 自動生成程式

public final class $Proxy0 extends Proxy implements Hello, World {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m4;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    
    // object 方法
    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);
        }
    }

    // object 方法
    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);
        }
    }

        // Hello 方法
    public final void talk(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

       // World 方法
    public final String say() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    // object 方法
    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 {
    //"1. "
        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("Hello").getMethod("talk", Class.forName("java.lang.String"));
            m4 = Class.forName("World").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());
        }
    }
}


A. 使用反射 getMethod (要看反射請點擊連結) 取得 Interface 中的 Function,並把 Method 存在內存中

B. 觀察它是如何調用 InvocationHandler 方法,可以看到我們在調用方法時都會調用 super.h.invoke (就是我們注入的 InvocationHandler 接口) (這樣就可以觀察到它每個參數的意思)


// 自動生成程式

     public final void talk(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String say() throws  {
        try {
          // 沒有參數可以傳 null
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }

C. 最後透過匿名內部類,做出方法調用的真正類 invoke(Object),並以與做加強


Object o = Proxy.newProxyInstance(pan.getClass().getClassLoader(),
                new Class[]{Hello.class, World.class},  // 不可代理類 String.class! 因為生成的類繼承 Proxy
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                        System.out.println("----------------get Invoke-------------------");
                        System.out.println("Method Name: " + method.getName());
                        //return method.invoke(o, objects);         // 不能自己代理自己
                        return method.invoke(pan, objects);
                    }
                }
        );

D. InvocationHandler 的返回是返回需要的參數 (它會強制轉型)


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

分析動態代理:輸出 Proxy 類

● 在動態代理中並沒有發現到被代理類有繼承 Proxy,只有代理類實現 InvocationHandler 接口,先分析被代理類是如何實現的


// 1. 呼叫 Proxy 建構
Proxy getProxy() {
        return (Proxy) Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
    }

// 2. Proxy 類
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();

        /*
         * Look up or generate the designated proxy class.
         */
         "1: "
        Class<?> cl = getProxyClass0(loader, intfs);

        try {
            // 創建內存的實例
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                // 檢查方法訪問權限
                cons.setAccessible(true);
            }

            "4: "return cons.newInstance(new Object[]{h});
        } ...
    }

// 分析第 1 點 getProxyClass0
 private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
             // 限制接口上限
            throw new IllegalArgumentException("interface limit exceeded");
        }

        "2. "
        return proxyClassCache.get(loader, interfaces);
    }

// 分析第 2 點的 WeakCache 類的 get
 public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        ...

        "3. "
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            ...
        }
 }

// 析第 3 點的 apply 是 BiFunction接口的方法,此接口由 Proxy.ProxyClassFactory 實現
public Class<?> apply(ClassLoader var1, Class<?>[] var2) {

            ...版本判別,處理兼容..

            "4: "
            long var19 = nextUniqueNumber.getAndIncrement();
            String var23 = var16 + "$Proxy" + var19;
            byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
            try {
                return Proxy.defineClass0(var1, var23, var22, 0, var22.length);
            } catch (ClassFormatError var14) {
                throw new IllegalArgumentException(var14.toString());
            }
        }

1. 分析如何取到 Class 對象

2. proxyClassCache 是 WeakCache 對象,是個泛型類


private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = 
new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

3. subKeyFactory 是 BiFunction 接口,是個泛型接口


private final BiFunction<K, P, ?> subKeyFactory

4. 利用原子操作(CAS) 創建類名,並透過 ProxyGenerator.generateProxyClass 創建 Class 再回返二進制文本,最後使用 defineClass0 (native類) 創建 Class

注意類名,$Proxy0 and $Proxy1

5. 利用反射的建構函數創建 Java 對象

UML

● 經過輸出流輸出了,ProxyGenerator 的數組(Java 反編譯 Class 流程


import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;

import sun.misc.ProxyGenerator;

public class startCoding {
    public static void main(String[] args) {

        ... 同上
        ProxyClassUnit.makeOutputClass(s1.getClass().getName(), s1.getClass());
        ProxyClassUnit.makeOutputClass(t1.getClass().getName(), t1.getClass());
    }
}

... 同上

class ProxyClassUnit {
    // ProxyGenerator.generateProxyClass(final String var0, Class<?>[] var1, int var2);
    static void makeOutputClass(String name, Class<?> clz) {
        byte[] clzBinary = ProxyGenerator.generateProxyClass(name, new Class[] {clz});

        String paths = clz.getResource(".").getPath();

        System.out.println("Path : " + name);
        System.out.println("Name : " + paths);

        try {
            // 輸出至目錄下
            OutputStream o = new FileOutputStream(paths + name + ".class");
            BufferedOutputStream bos = new BufferedOutputStream(o);

            bos.write(clzBinary);
            bos.flush();

            bos.close();
            o.close();
        } catch(Exception e) {
            e.printStackTrace();
        }

    }
}

// s1 輸出檔案
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 $Proxy0 {
  private static Method m1;

  private static Method m5;

  private static Method m3;

  private static Method m2;

  private static Method m6;

  private static Method m11;

  private static Method m13;

  private static Method m0;

  private static Method m8;

  private static Method m12;

  private static Method m7;

  private static Method m10;

  private static Method m4;

  private static Method m9;

  public $Proxy0(InvocationHandler paramInvocationHandler) {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject) {
    try {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final InvocationHandler getInvocationHandler(Object paramObject) throws IllegalArgumentException {
    try {
      return (InvocationHandler)this.h.invoke(this, m5, new Object[] { paramObject });
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final String getBook() {
    try {
      return (String)this.h.invoke(this, m3, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final String toString() {
    try {
      return (String)this.h.invoke(this, m2, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final Class getProxyClass(ClassLoader paramClassLoader, Class[] paramArrayOfClass) throws IllegalArgumentException {
    try {
      return (Class)this.h.invoke(this, m6, new Object[] { paramClassLoader, paramArrayOfClass });
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final Class getClass() {
    try {
      return (Class)this.h.invoke(this, m11, null);
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final void notifyAll() {
    try {
      this.h.invoke(this, m13, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final int hashCode() {
    try {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final void wait() throws InterruptedException {
    try {
      this.h.invoke(this, m8, null);
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final void notify() {
    try {
      this.h.invoke(this, m12, null);
      return;
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final Object newProxyInstance(ClassLoader paramClassLoader, Class[] paramArrayOfClass, InvocationHandler paramInvocationHandler) throws IllegalArgumentException {
    try {
      return this.h.invoke(this, m7, new Object[] { paramClassLoader, paramArrayOfClass, paramInvocationHandler });
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final void wait(long paramLong) throws InterruptedException {
    try {
      this.h.invoke(this, m10, new Object[] { Long.valueOf(paramLong) });
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final boolean isProxyClass(Class paramClass) {
    try {
      return ((Boolean)this.h.invoke(this, m4, new Object[] { paramClass })).booleanValue();
    } catch (Error|RuntimeException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  public final void wait(long paramLong, int paramInt) throws InterruptedException {
    try {
      this.h.invoke(this, m9, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
      return;
    } catch (Error|RuntimeException|InterruptedException error) {
      throw null;
    } catch (Throwable throwable) {
      throw new UndeclaredThrowableException(throwable);
    } 
  }

  static {
    try {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m5 = Class.forName("$Proxy0").getMethod("getInvocationHandler", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("$Proxy0").getMethod("getBook", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m6 = Class.forName("$Proxy0").getMethod("getProxyClass", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;") });
      m11 = Class.forName("$Proxy0").getMethod("getClass", new Class[0]);
      m13 = Class.forName("$Proxy0").getMethod("notifyAll", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m8 = Class.forName("$Proxy0").getMethod("wait", new Class[0]);
      m12 = Class.forName("$Proxy0").getMethod("notify", new Class[0]);
      m7 = Class.forName("$Proxy0").getMethod("newProxyInstance", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler") });
      m10 = Class.forName("$Proxy0").getMethod("wait", new Class[] { long.class });
      m4 = Class.forName("$Proxy0").getMethod("isProxyClass", new Class[] { Class.forName("java.lang.Class") });
      m9 = Class.forName("$Proxy0").getMethod("wait", new Class[] { long.class, int.class });
      return;
    } catch (NoSuchMethodException noSuchMethodException) {
      throw new NoSuchMethodError(noSuchMethodException.getMessage());
    } catch (ClassNotFoundException classNotFoundException) {
      throw new NoClassDefFoundError(classNotFoundException.getMessage());
    } 
  }
}

● 以上是 Proxy0 繼承了 Proxy 類並實作了 BookShop and Object 接口

getBook 這個方法的實現是透過調用 this.h,這個 h 是Proxy 中的 InvocationHandler,而這個 InvocationHandler 是由 CommonProxyShop 這個 class

結論 : 由代理類創造的動態代理 Proxy 類傳入的 InvocationHandler 會由 Proxy 類調用,接著讓使用者自己實現其方法

--實作--


更多的物件導向設計

物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!

設計建模 2 大概念- UML 分類、使用

物件導向設計原則 – 6 大原則(一)

物件導向設計原則 – 6 大原則(二)

創建、行為、結構型設計 8 個比較 | 包裝模式 | 最佳實踐

創建模式:Creation Patterns

創建模式 PK

創建模式 - Creation Patterns

結構模式:Structural Patterns

結構模式 PK

結構模式 - Structural Patterns

結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結

Bridge 橋接模式 | 解說實現 | 物件導向設計

Decorate 裝飾模式 | 解說實現 | 物件導向設計

Proxy 代理模式 | 解說實現 | 分析動態代理

Iterator 迭代設計 | 解說實現 | 物件導向設計

Facade 外觀、門面模式 | 解說實現 | 物件導向設計

Adapter 設計模式 | 解說實現 | 物件導向設計

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響