1. 程式人生 > >JAVA反射_代理

JAVA反射_代理

一、什麼是動態代理

動態代理可以提供對另一個物件的訪問,同時隱藏實際物件的具體事實。代理一般會實現它所表示的實際物件的介面。代理可以訪問實際物件,但是延遲實現實際物件的部分功能,實際物件實現系統的實際功能,代理物件對客戶隱藏了實際物件。客戶不知道它是與代理打交道還是與實際物件打交道。

目的:主要用來做方法的增強,讓你可以在不修改原始碼(不用改變這個方法的簽名,原來呼叫這個方法的類依然能正常工作)的情況下,增強一些方法。在方法執行前後做任何你想做的事情(甚至根本不去執行這個方法),因為在InvocationHandler的invoke方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用的話,比如可以新增呼叫日誌,做事務控制等。

還有一個有趣的作用是可以用作遠端呼叫,比如現在有Java介面,這個介面的實現部署在其它伺服器上,在編寫客戶端程式碼的時候,沒辦法直接呼叫介面方法,因為介面是不能直接生成物件的,這個時候就可以考慮代理模式(動態代理)了,通過Proxy.newProxyInstance代理一個該介面對應的InvocationHandler物件,然後在InvocationHandler的invoke方法內封裝通訊細節就可以了。具體的應用,最經典的當然是Java標準庫的RMI,其它比如hessian,各種webservice框架中的遠端呼叫,大致都是這麼實現的。
而像 AspectJ 這種 AOP 剛不同,它直接把人家的 class 程式碼修改了,它就不需要使用代理。
這些在新的 JDK 6 中都可以通過 Instrument 來做到,不過也是個通用的方法,還得通過規則來定製什麼情況下處理,什麼時候不處理。

二、jdk的動態代理
  目前Java開發包中包含了對動態代理的支援,但是其實現只支援對介面的的實現。 其實現主要通過java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler介面。 

Proxy類主要用來獲取動態代理物件,InvocationHandler介面用來約束呼叫者實現。

動態代理是很多框架和技術的基礎, spring 的AOP實現就是基於動態代理實現的。瞭解動態代理的機制對於理解AOP的底層實現是很有幫助的。



平常寫的程式碼,一般是一個物件直接持有另外一個物件的引用,稱為

靜態代理

public class StaticProxyMain {

    //這裡傳入的是介面型別的物件,方便向上轉型,實現多型
    public static void consumer(ProxyInterface pi){
        pi.say();
    }
    public static void main(String[] args) {
        StaticProxyMain.consumer(new ProxyObject());
    }
}


//代理介面
interface ProxyInterface{
    void say();
}


//被代理者
class RealObject implements ProxyInterface{
    //實現介面方法
    @Override
    public void say() {
        System.out.println("say");
    }

}


//代理者
class ProxyObject implements ProxyInterface{

    @Override
    public void say() {

        System.out.println("hello proxy");
        new RealObject().say();
        System.out.println("this is method end");
    }

}


動態代理:

例子1:

public class DProxyMain {

    public static void main(String[] args) {
        ArrayList<String> content = new ArrayList<>();
        MyInvocationHandler handler = new MyInvocationHandler(content);
        Object proxy = Proxy.newProxyInstance(null, new Class[]{List.class}, handler);

        if (proxy instanceof List) {
            System.out.println("proxy is list");

            List<String> mlist = (List<String>) proxy;
            mlist.add("one");
            mlist.add("two");
            mlist.add("three");
            mlist.add("apple");

        }

        System.out.println("proxy:"+proxy.toString());
        System.out.println("content:"+content.toString());
    }

}

class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("method name:"+method.getName());

        if (method.getName().equals("add")) {
            if (args[0].equals("apple")) {
                return false;
            }
        }


        return method.invoke(this.target, args);
    }
}

例子2:

public class DynamicProxyMain {

    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        ProxyInterface proxyInterface = (ProxyInterface) Proxy.newProxyInstance(ProxyInterface.class.getClassLoader(), new Class[]{ProxyInterface.class}, new ProxyObject(realObject));
        proxyInterface.say();
    }
}


//代理介面
interface ProxyInterface{
    void say();
}

//被代理類
class RealObject implements ProxyInterface {

    @Override
    public void say() {
        System.out.println("I'm talking...");
    }
}

//代理類,實現InvocationHandler 介面
class ProxyObject implements InvocationHandler {
    private Object target = null;

    public ProxyObject(Object proxied){
        this.target  = proxied;
    }


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

        return method.invoke(this.target, args);
    }
}


應用場景:

1. 利用動態代理實現設計模式,修飾器和介面卡

2. AOP程式設計(Spring AOP)