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.代理類的代碼邏輯和具體業務邏輯解耦,與業務無關;