1. 程式人生 > >JAVA中的JDK的動態代理

JAVA中的JDK的動態代理

在java的動態代理機制中,有兩個重要的類或介面,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class)

當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由InvocationHandler這個介面的 invoke 方法來進行呼叫。

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy: 指代我們所代理的那個真實物件

method: 指代的是我們所要呼叫真實物件的某個方法的Method物件

args

: 指代的是呼叫真實物件某個方法時接受的引數

 

接下來我們來看看Proxy這個類newProxyInstance 這個方法:

public static Object newProxyInstance

(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

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

loader: 一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入

interfaces: 一個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了

h: 一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上

示例程式碼:

/**
 * @program: Maven
 * @description: 介面
 * @author: hw
 * @create: 2018-12-07 17:00
 **/
public interface Subject {
    public void rent();

    public void hello(String str);
}




/**
 * @program: Maven
 * @description: 真實物件
 * @author: hw
 * @create: 2018-12-07 17:00
 **/
public class RealSubject implements Subject {
    @Override
    public void rent() {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str) {
        System.out.println("hello: " + str);
    }
}

動態代理類

/**
 * @program: Maven
 * @description: 動態代理類
 * @author: hw
 * @create: 2018-12-07 17:01
 **/
public class DynamicProxy implements InvocationHandler {
    // 這個就是我們要代理的真實物件
    private Object subject;
    //    構造方法,給我們要代理的真實物件賦初值
    public DynamicProxy(Object subject) {
        this.subject = subject;
    }
    @Override
    public Object invoke(Object object, Method method, Object[] args)
            throws Throwable {
        //  在代理真實物件前我們可以新增一些自己的操作
        System.out.println("before rent house");
        System.out.println("Method:" + method);
        //    當代理物件呼叫真實物件的方法時,
        // 其會自動的跳轉到代理物件關聯的handler物件的invoke方法來進行呼叫
        method.invoke(subject, args);
        //  在代理真實物件後我們也可以新增一些自己的操作
        System.out.println("after rent house");
        return null;
    }
}

測試類

/**
 * @program: Maven
 * @description: 測試
 * @author: hw
 * @create: 2018-12-07 17:01
 **/
public class Client {
    public static void main(String[] args) {
        //    我們要代理的真實物件
        Subject realSubject = new RealSubject();
        //    我們要代理哪個真實物件,就將該物件傳進去,最後是通過該真實物件來呼叫其方法的
        InvocationHandler handler = new DynamicProxy(realSubject);
        /*
         * 通過Proxy的newProxyInstance方法來建立我們的代理物件,我們來看看其三個引數
         * 第一個引數 handler.getClass().getClassLoader() ,
         * 我們這裡使用handler這個類的ClassLoader物件來載入我們的代理物件
         *
         * 第二個引數realSubject.getClass().getInterfaces(),
         * 我們這裡為代理物件提供的介面是真實物件所實行的介面,
         * 表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了
         *
         * 第三個引數handler, 我們這裡將這個代理物件關聯到了上方的 InvocationHandler
         * 這個物件上
         */
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);
        System.out.println(subject.getClass().getName());
        //呼叫方法
        subject.rent();
        subject.hello("world");
    }
}