代理模式也稱為委托模式陡鹃,其實代理在我們?nèi)粘I钪胁⒉簧僖姾嫫郑瑢τ诔绦騿T來說最常接觸的莫過于代理上網(wǎng)了,代理模式在開發(fā)過程使用非常普遍.
通用模式代碼:
public abstract class Subject {
public abstract void visit();
}
public class RealSubject extends Subject {
@Override
public void visit() {
System.out.println("Real subject!");
}
}
public class ProxySubject extends Subject {
private RealSubject mSubject;
public ProxySubject(RealSubject subject){
this.mSubject = subject;
}
@Override
public void visit() {
}
}
public class Client {
public static void main(String[] args){
//構(gòu)造一個真實主題對象
RealSubject realSubject = new RealSubject();
//通過真實主題對象構(gòu)造一個代理對象
ProxySubject proxySubject = new ProxySubject(realSubject);
//調(diào)用代理的相關(guān)方法
proxySubject.visit();
}
}
角色介紹:
Subject : 抽象主題類
該類的主要職責是聲明真實主題與代理的共同接口方法萍鲸,該類可以是一個抽象類也可以是一個接口
RealSubject : 真實主題類
該類也成為被委托類或被代理類闷叉,該類定義了代理所表示的真實對象,???執(zhí)行具體的業(yè)務(wù)邏輯方法脊阴,而客戶類通過代理類間接地調(diào)用真實主題類中定義的方法
ProxySubject :代理類
該類也稱為委托類或代理類握侧,該類持有一個對真實主題類的引用,在其所實現(xiàn)的接口方法中調(diào)用真實主題類中相應(yīng)的接口方法執(zhí)行蹬叭,以此起到代理的作用
Client : 客戶類 使用代理類的類
代理模式的簡單實現(xiàn)
小明被拖欠工資藕咏,想走法律程序状知,找律師去申述這一個過程秽五,使用代理模式律師就是代理者,小明就是被代理的者饥悴,下面看看這樣一個過程坦喘,代碼應(yīng)該怎樣去實現(xiàn).
public interface ILawsuit {
//提交申請
void submit();
//進行舉證
void burden();
//開始維護
void defend();
//訴訟完成
void finish();
}
public class XiaoMin implements ILawsuit{
@Override
public void submit() {
//老板欠小民工資 小小民只好申請仲裁
System.out.println("老板拖欠工資,特此申請仲裁");
}
@Override
public void burden() {
//小民證據(jù)充足西设,不怕告不贏
System.out.println("這是合同書和過去一年的銀行工資流水");
}
@Override
public void defend() {
//鐵證如山瓣铣,辯護也沒什么好說的
System.out.println("證據(jù)確鑿! 不需要再說什么了");
}
@Override
public void finish() {
//結(jié)果也是肯定的,必贏
System.out.println("訴訟成功! 判決老板即日起七天內(nèi)結(jié)算工資");
}
}
public class Lawyer implements ILawsuit{
private ILawsuit mILawsuit;
public Lawyer(ILawsuit mILawsuit) {
this.mILawsuit = mILawsuit;
}
@Override
public void submit() {
}
@Override
public void burden() {
}
@Override
public void defend() {
}
@Override
public void finish() {
}
}
public class Client {
public static void main(String[] args){
ILawsuit xiaomin = new XiaoMin();
//構(gòu)造代理律師
ILawsuit lawsuit = new Lawyer(xiaomin);
//律師提交訴訟申請
lawsuit.submit();
//律師進行舉證
lawsuit.burden();
//律師代替小民進行辯護
lawsuit.defend();
//完成訴訟
lawsuit.finish();
}
}
代理模式是一個非常重要的模式,它可以分為靜態(tài)代理和動態(tài)代理贷揽,靜態(tài)代理如上面所訴棠笑,代理類的代碼由開發(fā)者自己編寫;動態(tài)代理則與靜態(tài)代理相反禽绪,通過反射機制動態(tài)地生成代理者的對象蓖救,也就是我們code階段壓根就不需要知道代理誰,代理誰我們將會執(zhí)行階段決定.
下面繼續(xù)看
我們使用動態(tài)代理印屁,首先要定義一個InvocationHandler的子類循捺,我們命名為DynamicProxy
public class DynamicProxy implements InvocationHandler{
private Object obj; //被代理的類引用
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//調(diào)用被代理類對象的方法
Object result = method.invoke(obj,args);
return result;
}
}
下面看下如何使用這個動態(tài)代理
public class Client {
public static void main(String[] args){
//構(gòu)造一個小民
ILawsuit xiaomin = new XiaoMin();
//構(gòu)造一個動態(tài)代理
DynamicProxy proxy = new DynamicProxy(xiaomin);
//獲取被代理類小民的ClassLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//動態(tài)構(gòu)造一個代理者律師
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},proxy);
//律師提交訴訟申請
lawyer.submit();
//律師進行舉證
lawyer.burden();
//律師代替小民進行辯護
lawyer.defend();
//完成訴訟
lawyer.finish();
}
}
輸出和前面靜態(tài)代理是一樣的,不過上面代碼可能還是有點疑惑雄人,我們一一解答下下面幾個問題
問題一:InvocationHandler在這個動態(tài)代理里面起到什么作用从橘?為什么通過Proxy.newProxyInstance可以生成一個動態(tài)代理對象?
解釋這一點,我們就需要去看看源代碼了,先看看InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler就是一個接口恰力,里面有一個接口方法invoke叉谜,并傳入三個參數(shù)Object proxy, Method method, Object[] args。Object這種參數(shù)就不用說了踩萎,下面來看看Method到底是什么正罢,根據(jù)Method上面的注釋
/**
* A {@code Method} provides information about, and access to, a single method
* on a class or interface. The reflected method may be a class method
* or an instance method (including an abstract method).
*/
public final class Method extends Executable {
}
它主要是獲取一個方法相關(guān)的信息,比如說getName()獲取方法名,getReturnType()獲取方法返回類型這些. 單單一個InvocationHandler其實也看不出來它的工作原理驻民,下面我們來看看newProxyInstance的源碼
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//1如果InvocationHandler為null就直接拋異常
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
//2獲取代理類
Class<?> cl = getProxyClass0(loader, intfs);
try {
//3獲得構(gòu)造器
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
// Android-changed: Removed AccessController.doPrivileged
cons.setAccessible(true);
}
//4實例話代理類翻具,注意這里傳入了InvocationHandler
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
//代碼省略
}
}
上面的代碼我們重點需要關(guān)注以下注釋2和注釋4,先來看看注釋2回还,如何獲取代理類裆泳,我們點擊去看
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
通過proxyClassCache.get返回,proxyClassCache是什么柠硕?
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
再來看看get怎么實現(xiàn)的
//這里key class loader parameter是interface
public V get(K key, P parameter) {
//1如果傳入interface參數(shù)為null就直接返回
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
上面代碼我們其實就是一個沒有cache的時候put進去工禾,然后get, 有cache的時候就直接get這樣一個過程,我們重點看看它put和get什么就清楚最終它返回的是一個什么樣的代理類.
put(來自于上面源碼)
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
}
get(來自于上面源碼)
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
其實put是存入Factory蝗柔,get呢是調(diào)用Factory的.get(Factory是Supplier的子類), 那么實際返回的代理類就是來自于Factory的get咯.
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
//******************關(guān)注這里*******************
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// try replacing us with CacheValue (this should always succeed)
if (valuesMap.replace(subKey, this, cacheValue)) {
// put also in reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
上面的valueFactory是ProxyClassFactory闻葵,ProxyClassFactory調(diào)用apply源碼如下
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//代碼省略
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
@FastNative
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
ClassLoader loader, Method[] methods,
Class<?>[][] exceptions);
generateProxy是native方法
我還不會跟進到native層,所以也不能繼續(xù)分析了. 不過總而言之getProxyClass0通過native層返回了一個代理類癣丧,注意這是個新類槽畔,里面有傳入的ClassLoader和interfaces作為成員變量,下面再來看看注釋4實例話代理類
cons.newInstance(new Object[]{h});
這里我們獲取到代理類后胁编,直接傳入?yún)?shù)h(InvocationHandler), 返回代理對象了.
最后結(jié)論是:native實現(xiàn)機制我暫時還不太清楚厢钧,不過大概來說native返回的代理對象會對被代理對象和InvocationHandler做一個關(guān)聯(lián),使得被代理對象沒調(diào)用一個函數(shù)都會回調(diào)到InvocationHandler的invoke方法中嬉橙,從而進行一個動態(tài)代理操作.
問題二早直,動態(tài)代理比靜態(tài)代理優(yōu)越在哪,什么時候使用動態(tài)代理市框?
通過實現(xiàn)和調(diào)用方式來看霞扬,使用動態(tài)代理就不需要再去定義靜態(tài)代理類了,代理過程是一個動態(tài)的適配枫振,在InvocationHandler的invoke去決定如何做這個代理過程. 什么時候用動態(tài)代理我覺得如果你的代理類存在很多喻圃,不方便用靜態(tài)實現(xiàn),就可以使用動態(tài)代理, 在Android中Retrofit框架就使用了動態(tài)代理技術(shù)蒋得,通常我們這樣創(chuàng)建Interface對象
PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);
進入create源碼
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
它的所有動態(tài)代理邏輯都集中在
serviceMethod.callAdapter.adapt(okHttpCall)
詳情在這里也不多說了级及,大概就是這樣.
Android中的代理模式實現(xiàn)
我們來看看ActivityManagerProxy這個類,其具體代理的是ActivityManagerNative的子類ActivityManagerService.
ActivityManagerProxy實現(xiàn)了IActivityManager接口额衙,該接口定義了一些Activity相關(guān)的接口方法饮焦,其中有一些我們在應(yīng)用開發(fā)中也時常接觸到.
IActivityManager這個接口相當于代理模式中的抽象主題怕吴,那么真正的實現(xiàn)主題是ActivityManagerNative的ActivityManagerService類,這幾個類大致的關(guān)系:
ActivityManagerProxy實際上代理的是ActivityManagerService县踢,但是ActivityManagerProxy和ActivityManagerService是分別運行在不同的進程里(ActivityManagerProxy是運行在應(yīng)用的進程转绷,而ActivityManagerService是運行在系統(tǒng)進程),所以它們之間的這個代理過程是跨進程的硼啤,這里跨進程是用到Android的Binder集中完成. 不過ActivityManagerProxy在實際邏輯處理中并未過多地被外部類使用议经,因為在Android中管理與維護Activity相關(guān)信息的類是另外一個叫做ActivityManager的類,ActivityManager雖然說管理著Activity信息谴返,但是實質(zhì)上大多數(shù)邏輯由ActivityManagerProxy承擔煞肾,這里以其中的getAppTasks方法為例,在ActivityManager中g(shù)etAppTasks方法邏輯如下.
public List<ActivityManager.AppTask> getAppTasks() {
ArrayList<AppTask> tasks = new ArrayList<AppTask>();
List<IBinder> appTasks;
try {
appTasks = getService().getAppTasks(mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
int numAppTasks = appTasks.size();
for (int i = 0; i < numAppTasks; i++) {
tasks.add(new AppTask(IAppTask.Stub.asInterface(appTasks.get(i))));
}
return tasks;
}
getService()其實返回的是一個IActivityManager嗓袱,那這個IActivityManager的實體類是什么呢籍救?
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
ServiceManager.getService()返回的是一個系統(tǒng)級的Service, 這個Service實際上是ActivityManagerService,這里也完成創(chuàng)建一個對ActivityManagerService的Client代理對象ActivityManagerProxy實例.ActivityManagerProxy中的getAppTasks方法邏輯就很明確,將數(shù)據(jù)打包跨進程傳遞給Server端ActivityManagerService處理并返回結(jié)果.
public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(callingPackage);
mRemote.transact(GET_APP_TASKS_TRANSACTION, data, reply, 0);
reply.readException();
ArrayList<IAppTask> list = null;
int N = reply.readInt();
if (N >= 0) {
list = new ArrayList<>();
while (N > 0) {
IAppTask task = IAppTask.Stub.asInterface(reply.readStrongBinder());
list.add(task);
N--;
}
}
data.recycle();
reply.recycle();
return list;
}
再來看看ActivityManagerService中的getAppTasks
@Override
public List<IAppTask> getAppTasks(String callingPackage) {
int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
synchronized(this) {
ArrayList<IAppTask> list = new ArrayList<IAppTask>();
try {
if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");
final int N = mRecentTasks.size();
for (int i = 0; i < N; i++) {
TaskRecord tr = mRecentTasks.get(i);
// Skip tasks that do not match the caller. We don't need to verify
// callingPackage, because we are also limiting to callingUid and know
// that will limit to the correct security sandbox.
if (tr.effectiveUid != callingUid) {
continue;
}
Intent intent = tr.getBaseIntent();
if (intent == null ||
!callingPackage.equals(intent.getComponent().getPackageName())) {
continue;
}
ActivityManager.RecentTaskInfo taskInfo =
createRecentTaskInfoFromTaskRecord(tr);
AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
list.add(taskImpl);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return list;
}
}
Android中的Binder跨進程通信機制
在Android中進程間通信我們通常使用到的是binder機制渠抹,binder機制所使用到的四個基本模塊是Binder Client, Binder Server, ServerManager和Binder Driver,這四者之間的關(guān)系類似與網(wǎng)絡(luò)訪問蝙昙,Binder Client相當于我們的客戶端pc , Binder Server相當于服務(wù)器,ServerManager相當于DNS服務(wù)器梧却,而Binder Driver則相當于一個路由器奇颠。其中Binder Driver實現(xiàn)在內(nèi)核空間中,而其余3者Binder Client, Binder Server, ServerManager實現(xiàn)在用戶空間中.
Binder Client與Binder Server之間的跨進程通信統(tǒng)一通過Binder Driver處理轉(zhuǎn)發(fā)放航,對于Binder Client來說烈拒,其只需要知道自己要使用的Binder的名字以及該Binder實體在ServerManager中的0號引用即可,訪問原理也比較簡單三椿,Binder Client先是通過0號引用去訪問ServerManager獲取Binder的引用缺菌,得到引用后就可以像普通方法那樣調(diào)用Binder實體方法。最后我們的ServerManager則用來管理Binder Server, Binder Client可以通過它來查詢Binder Server接口搜锰,剛才提到過Binder Client可以通過ServerManager來獲取Binder的引用,這個Binder引用就是由ServerManager來轉(zhuǎn)換的耿战。
如果再繼續(xù)說下去就有點蒙圈了. 還是按照簡單易懂的說法吧:
看這里蛋叼,你可以想象成Binder Driver就是一個管道,ServerManager是一個注冊表剂陡,所有的Binder Client和Binder Server都要在它那里注冊狈涮,Binder Client也通過ServerManager去查找對應(yīng)的Binder Server
最后,Binder Client和Binder Server其實實現(xiàn)的接口是一樣的鸭栖,所以大家可以聯(lián)想到Binder機制其實也是一種代理模式.
總結(jié)
代理模式是一種使用比較多的一種結(jié)構(gòu)性設(shè)計模式歌馍,這節(jié)通過一個通用模式代碼講解了代理模式的基本實現(xiàn)方案,然后又引入了一個小民打官司的栗子晕鹊,講解了如何去實現(xiàn)靜態(tài)代理和動態(tài)代理松却,然后深入了解了動態(tài)代理的實現(xiàn)原理和用處暴浦,最后講解了Android中有哪些地方用到了代理模式實現(xiàn).