1. 程式人生 > >JAVA動態代理機制解析

JAVA動態代理機制解析

定義 book lang 並不是 stat 控制 () highlight 什麽

1. 概述
  首先,我們來思考如下兩個問題:
  什麽是代理模式?為什麽要使用代理模式?

  簡單總結一下,所謂的代理模式就是在原有的服務上多加一個占位,通過這個占位去控制服務的訪問。通過代理模式,一方面可以控制如何訪問真正的服務對象,提供額外服務;另一方面,有機會通過重寫一些類來滿足特定的需要。

  在java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現動態代理所必須用到的。下面我們具體分析一下:
  (1)InvocationHandler接口:當通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由InvocationHandler接口的 invoke 方法來進行調用。InvocationHanler的 invoke 方法如下:
  Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  三個參數的具體含義如下:
    proxy:  代理的真實對象
    method: 調用真實對象的某個方法的Method對象
    args:  調用真實對象某個方法時接收的參數

  (2)Proxy類:這個類的作用就是用來動態創建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法,如下:
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

  這個方法的作用就是得到一個動態的代理對象,其接收三個參數,我們來看看這三個參數所代表的含義:

    loader: 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載;
    interfaces: 一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什麽接口,如果我提供了一組接口給它,那麽這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了;
    h:  一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上

2. 示例

  (1)我們先定義一個接口:

public interface Library {
    void isAvalid();
    void sayHello(String name);
}

  (2)接口的實現類:

public class Book implements Library {
    @Override
    public void isAvalid() {
        System.out.println("This book can be borrowed! ");
    }

    @Override
    public void sayHello(String name) {
        System.out.println("Book name is: "+ name);
    }
}

  (3)動態代理:

public class DynamicProxy implements InvocationHandler {
    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Bollow flow begin...");
        System.out.println("Method name is: "+ method);

        method.invoke(object, args);

        System.out.println("Bollow flow end...");
        return null;
    }
}

  (4)測試類:

public class Reader {
    public static void main(String[] args) {
        Book book = new Book();
        InvocationHandler handler = new DynamicProxy(book);

        Library library = (Library) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                book.getClass().getInterfaces(), handler);

        System.out.println(library.getClass().getName());
        library.isAvalid();
        library.sayHello("<JAVA Concurrency In Practice>");
    }
}
結果輸出:
$Proxy0
Bollow flow begin...
Method name is: public abstract void com.cn.dynamicProxy.Library.isAvalid()
This book can be borrowed! 
Bollow flow end...
Bollow flow begin...
Method name is: public abstract void com.cn.dynamicProxy.Library.sayHello(java.lang.String)
Book name is: <JAVA Concurrency In Practice>
Bollow flow end...

說明:

  通過 Proxy.newProxyInstance 創建的代理對象是在jvm運行時動態生成的一個對象,它並不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運行是動態生成的一個對象,並且命名方式都是這樣的形式,以$開頭,proxy為中,最後一個數字表示對象的標號。

  實際的運行方法:
    Method name is: public abstract void com.cn.dynamicProxy.Library.isAvalid()
    Method name is: public abstract void com.cn.dynamicProxy.Library.sayHello(java.lang.String)
  所以,當我通過代理對象來調用方法的時候,實際上就是委托由其關聯到的 handler 對象的invoke方法中來調用,並不是自己來真實調用,而是通過代理的方式來調用的。這就是java的動態代理機制。

JAVA動態代理機制解析