1. 程式人生 > >Java動態代理--Proxy.newProxyInstance

Java動態代理--Proxy.newProxyInstance

一、代理模式

主要用來做方法的增強,讓你可以在不修改原始碼的情況下,增強一些方法,在方法執行前後做任何你想做的事情(甚至根本不去執行這個方法),因為在InvocationHandler的invoke方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用的話,比如可以新增呼叫日誌,做事務控制等。動態代理是設計模式當中代理模式的一種。

package proxy;

public interface Subject {
    /**
     * 想在hello這個方法前後執行 相應的列印邏輯
     * @param str
     */
    public void hello(String str);
}

package proxy;

public class RealSubject implements Subject {
    
    @Override
    public void hello(String str) {

        System.out.println("hello: " + str);
    }
}
package proxy;

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

public class DynamicProxy implements InvocationHandler {
    //這個就是我們要代理的真實物件
    private Object subject;
    
    //構造方法,給我們要代理的真實物件賦初值
    public DynamicProxy(Object subject)
    {
        this.subject = subject;
    }

    /**
     *
     * @param object 指代我們所代理的那個真實物件
     * @param method 指代的是我們所要呼叫真實物件的某個方法的Method物件
     * @param args 指代的是呼叫真實物件某個方法時接受的引數
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        //  在代理真實物件前我們可以新增一些自己的操作
        System.out.println("before hello===============");
        
        System.out.println("Method:" + method);
        
        //當代理物件呼叫真實物件的方法(subject.rent();和subject.hello("world");)時,實際上執行的都是該invoke方法裡面的程式碼
        //public Object invoke(Object object, Method method, Object[] args) throws Throwable
        method.invoke(subject, args);
        
        //  在代理真實物件後我們也可以新增一些自己的操作
        System.out.println("after hello===============");
        
        return null;
    }

}

 

package proxy;

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

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物件來載入我們的代理物件
         * 一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入
         *
         * 第二個引數realSubject.getClass().getInterfaces(),我們這裡為代理物件提供的介面是真實物件所實行的介面,
         * 表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了
         * 一個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,
         * 那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了
         *
         * 第三個引數handler, 我們這裡將這個代理物件關聯到了上方的 InvocationHandler 這個物件上
         * 一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上
         */
        Subject subject = (
                Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                handler);
        
        System.out.println(subject.getClass().getName());
        subject.hello("world");
    }
}

列印結果:

com.sun.proxy.$Proxy0
before hello===============
Method:public abstract void proxy.Subject.hello(java.lang.String)
hello: world
after hello===============

Process finished with exit code 0