Android 靜態代理和動態代理

Android 靜態代理和動態代理

代理模式定義:爲其他對象提供一種代理以控制這個對象的訪問

靜態代理

靜態代理比較簡單,看下下面的代碼就很好理解

//定義一個接口
public interface Subject {
    void sayGoodBye();
    void sayHello(String str);
}
//定義一個被代理的類
public class RealSubject implements Subject {
    @Override
    public void sayGoodBye() {
        System.out.println("RealSubject sayGoodBye");
    }

    @Override
    public void sayHello(String str) {
        System.out.println("RealSubject sayHello  " + str);
    }
}
//代理類
public class ProxySubject implements Subject {

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void sayGoodBye() {
        //代理類,功能的增強
        System.out.println("ProxySubject sayGoodBye begin");
        //在代理類的方法中 間接訪問被代理對象的方法
        subject.sayGoodBye();
        System.out.println("ProxySubject sayGoodBye end");
    }

    @Override
    public void sayHello(String str) {
        //代理類,功能的增強
        System.out.println("ProxySubject sayHello begin");
        //在代理類的方法中 間接訪問被代理對象的方法
        subject.sayHello(str);
        System.out.println("ProxySubject sayHello end");
    }
}

使用方法

//被代理對象,某些情況,我們不希望修改已有代碼,我們採用代理來間接訪問
RealSubject realSubject = new RealSubject();
//代理類對象
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.sayGoodBye();
proxySubject.sayHello("Test");

輸出結果
ProxySubject sayGoodBye begin
RealSubject sayGoodBye
ProxySubject sayGoodBye end
ProxySubject sayHello begin
RealSubject sayHello Test
ProxySubject sayHello end

動態代理

動態代理也叫做jdk代理、接口代理,不需要實現目標對象的接口。生成代理對象,使用的是Java的API,動態的在內存中構建代理對象。

1、在java的動態代理機制中,有兩個重要的類或接口
一個是 InvocationHandler(Interface)
另一個則是Proxy(Class)
這一個類和接口是實現我們動態代理所必須用到的
2、 InvocationHandler

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

proxy:指代生成的代理對象;
method:指代的是我們所要調用真實對象的某個方法的Method對象;
args:指代的是調用真實對象某個方法時接受的參數;

每一個代理實類例的invocation handler都要實現InvocationHandler這個接口。並且每個代理類的實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的invoke 方法來進行調用

3、 Proxy這個類的 newProxyInstance 這個方法
JDK動態代理需要藉助接口來實現,如果我們要代理的對象功能沒有抽成任何接口,那麼我們就無法通過JDK動態代理的方式來實現。

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

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

第一步:定義一個接口
//定義一個接口
public interface Subject {
    void sayGoodBye();
    void sayHello(String str);
}
第二步:定義真是對象(被代理類):
//定義一個被代理的類
public class RealSubject implements Subject {
    @Override
    public void sayGoodBye() {
        System.out.println("RealSubject sayGoodBye");
    }

    @Override
    public void sayHello(String str) {
        System.out.println("RealSubject sayHello  " + str);
    }
}
第三步: 定義一個InvocationHandler, 相當於一個代理處理器

SubjectInvocationHandler並不是真正的代理類,而是用於定義代理類需要擴展、增強那些方法功能的類。在invoke函數中,對代理對象的所有方法的調用都被轉發至該函數處理。在這裏可以靈活的自定義各種你能想到的邏輯。

public class SubjectInvocationHandler implements InvocationHandler {
    //這個就是我們要代理的真實對象
    private Object subject;
    //構造方法,給我們要代理的真實對象賦初值
    public SubjectInvocationHandler(Object subject) {
        this.subject = subject;
    }
    @Override
    public Object invoke(Object object, Method method, Object[] args) throws Throwable {
        //在代理真實對象前我們可以添加一些自己的操作
        System.out.println("before Method invoke");
        System.out.println("Method:" + method);
        //當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用
        method.invoke(subject, args);
        //在代理真實對象後我們也可以添加一些自己的操作
        System.out.println("after Method invoke");
        return null;
    }
}
第四步:調用
//被代理類
Subject realSubject = new RealSubject();
//我們要代理哪個類,就將該對象傳進去,最後是通過該被代理對象來調用其方法的
SubjectInvocationHandler handler = new SubjectInvocationHandler(realSubject);
//生成代理類
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                                                          realSubject.getClass().getInterfaces(), handler);
//輸出代理類對象
System.out.println("Proxy : "+ subject.getClass().getName());
System.out.println("Proxy super : "+ subject.getClass().getSuperclass().getName());
System.out.println("Proxy interfaces : "+ subject.getClass().getInterfaces()[0].getName());
//調用代理類sayGoodBye方法
subject.sayGoodBye();
System.out.println("--------");
//調用代理類sayHello方法
subject.sayHello("Test");
   結果:
   Proxy super : java.lang.reflect.Proxy
    Proxy interfaces : com.company.ha.Subject
    before Method invoke
    Method:public abstract void com.company.ha.Subject.sayGoodBye()
    RealSubject sayGoodBye
    after Method invoke
    --------
    before Method invoke
    Method:public abstract void com.company.ha.Subject.sayHello(java.lang.String)
    RealSubject sayHello  Test
    after Method invoke

總結:

與靜態代理相比,動態代理具有如下的優點:

1.代理轉發的過程自動化了,實現自動化搬磚;
2.代理類的代碼邏輯和具體業務邏輯解耦,與業務無關;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章