Android源码设计模式学习笔记-代理模式
代理模式也称为委托模式,其实代理在我们日常生活中并不少见,对于程序员来说最常接触的莫过于代理上网了,代理模式在开发过程使用非常普遍.
image.png
通用模式代码:
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){
//构造一个真实主题对象
RealSubject realSubject = new RealSubject();
//通过真实主题对象构造一个代理对象
ProxySubject proxySubject = new ProxySubject(realSubject);
//调用代理的相关方法
proxySubject.visit();
}
}
角色介绍:
Subject : 抽象主题类
该类的主要职责是声明真实主题与代理的共同接口方法,该类可以是一个抽象类也可以是一个接口
RealSubject : 真实主题类
该类也成为被委托类或被代理类,该类定义了代理所表示的真实对象,🈶️执行具体的业务逻辑方法,而客户类通过代理类间接地调用真实主题类中定义的方法
ProxySubject :代理类
该类也称为委托类或代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行,以此起到代理的作用
Client : 客户类 使用代理类的类
代理模式的简单实现
小明被拖欠工资,想走法律程序,找律师去申述这一个过程,使用代理模式律师就是代理者,小明就是被代理的者,下面看看这样一个过程,代码应该怎样去实现.
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() {
//小民证据充足,不怕告不赢
System.out.println("这是合同书和过去一年的银行工资流水");
}
@Override
public void defend() {
//铁证如山,辩护也没什么好说的
System.out.println("证据确凿! 不需要再说什么了");
}
@Override
public void finish() {
//结果也是肯定的,必赢
System.out.println("诉讼成功! 判决老板即日起七天内结算工资");
}
}
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();
//构造代理律师
ILawsuit lawsuit = new Lawyer(xiaomin);
//律师提交诉讼申请
lawsuit.submit();
//律师进行举证
lawsuit.burden();
//律师代替小民进行辩护
lawsuit.defend();
//完成诉讼
lawsuit.finish();
}
}
代理模式是一个非常重要的模式,它可以分为静态代理和动态代理,静态代理如上面所诉,代理类的代码由开发者自己编写;动态代理则与静态代理相反,通过反射机制动态地生成代理者的对象,也就是我们code阶段压根就不需要知道代理谁,代理谁我们将会执行阶段决定.
下面继续看
image.png
我们使用动态代理,首先要定义一个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 {
//调用被代理类对象的方法
Object result = method.invoke(obj,args);
return result;
}
}
下面看下如何使用这个动态代理
public class Client {
public static void main(String[] args){
//构造一个小民
ILawsuit xiaomin = new XiaoMin();
//构造一个动态代理
DynamicProxy proxy = new DynamicProxy(xiaomin);
//获取被代理类小民的ClassLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//动态构造一个代理者律师
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader,new Class[]{ILawsuit.class},proxy);
//律师提交诉讼申请
lawyer.submit();
//律师进行举证
lawyer.burden();
//律师代替小民进行辩护
lawyer.defend();
//完成诉讼
lawyer.finish();
}
}
输出和前面静态代理是一样的,不过上面代码可能还是有点疑惑,我们一一解答下下面几个问题
问题一:InvocationHandler在这个动态代理里面起到什么作用?为什么通过Proxy.newProxyInstance可以生成一个动态代理对象?
解释这一点,我们就需要去看看源代码了,先看看InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler就是一个接口,里面有一个接口方法invoke,并传入三个参数Object proxy, Method method, Object[] args。Object这种参数就不用说了,下面来看看Method到底是什么,根据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 {
}
它主要是获取一个方法相关的信息,比如说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获得构造器
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) {
//代码省略
}
}
上面的代码我们重点需要关注以下注释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怎么实现的
//这里key class loader parameter是interface
public V get(K key, P parameter) {
//1如果传入interface参数为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呢是调用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 {
//******************关注这里*******************
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调用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方法
image.png
我还不会跟进到native层,所以也不能继续分析了. 不过总而言之getProxyClass0通过native层返回了一个代理类,注意这是个新类,里面有传入的ClassLoader和interfaces作为成员变量,下面再来看看注释4实例话代理类
cons.newInstance(new Object[]{h});
这里我们获取到代理类后,直接传入参数h(InvocationHandler), 返回代理对象了.
最后结论是:native实现机制我暂时还不太清楚,不过大概来说native返回的代理对象会对被代理对象和InvocationHandler做一个关联,使得被代理对象没调用一个函数都会回调到InvocationHandler的invoke方法中,从而进行一个动态代理操作.
问题二,动态代理比静态代理优越在哪,什么时候使用动态代理?
通过实现和调用方式来看,使用动态代理就不需要再去定义静态代理类了,代理过程是一个动态的适配,在InvocationHandler的invoke去决定如何做这个代理过程. 什么时候用动态代理我觉得如果你的代理类存在很多,不方便用静态实现,就可以使用动态代理, 在Android中Retrofit框架就使用了动态代理技术,通常我们这样创建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);
}
});
}
它的所有动态代理逻辑都集中在
serviceMethod.callAdapter.adapt(okHttpCall)
详情在这里也不多说了,大概就是这样.
Android中的代理模式实现
我们来看看ActivityManagerProxy这个类,其具体代理的是ActivityManagerNative的子类ActivityManagerService.
ActivityManagerProxy实现了IActivityManager接口,该接口定义了一些Activity相关的接口方法,其中有一些我们在应用开发中也时常接触到.
IActivityManager这个接口相当于代理模式中的抽象主题,那么真正的实现主题是ActivityManagerNative的ActivityManagerService类,这几个类大致的关系:
image.png
ActivityManagerProxy实际上代理的是ActivityManagerService,但是ActivityManagerProxy和ActivityManagerService是分别运行在不同的进程里(ActivityManagerProxy是运行在应用的进程,而ActivityManagerService是运行在系统进程),所以它们之间的这个代理过程是跨进程的,这里跨进程是用到Android的Binder集中完成. 不过ActivityManagerProxy在实际逻辑处理中并未过多地被外部类使用,因为在Android中管理与维护Activity相关信息的类是另外一个叫做ActivityManager的类,ActivityManager虽然说管理着Activity信息,但是实质上大多数逻辑由ActivityManagerProxy承担,这里以其中的getAppTasks方法为例,在ActivityManager中getAppTasks方法逻辑如下.
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()返回的是一个系统级的Service, 这个Service实际上是ActivityManagerService,这里也完成创建一个对ActivityManagerService的Client代理对象ActivityManagerProxy实例.ActivityManagerProxy中的getAppTasks方法逻辑就很明确,将数据打包跨进程传递给Server端ActivityManagerService处理并返回结果.
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,这四者之间的关系类似与网络访问,Binder Client相当于我们的客户端pc , Binder Server相当于服务器,ServerManager相当于DNS服务器,而Binder Driver则相当于一个路由器。其中Binder Driver实现在内核空间中,而其余3者Binder Client, Binder Server, ServerManager实现在用户空间中.
Binder Client与Binder Server之间的跨进程通信统一通过Binder Driver处理转发,对于Binder Client来说,其只需要知道自己要使用的Binder的名字以及该Binder实体在ServerManager中的0号引用即可,访问原理也比较简单,Binder Client先是通过0号引用去访问ServerManager获取Binder的引用,得到引用后就可以像普通方法那样调用Binder实体方法。最后我们的ServerManager则用来管理Binder Server, Binder Client可以通过它来查询Binder Server接口,刚才提到过Binder Client可以通过ServerManager来获取Binder的引用,这个Binder引用就是由ServerManager来转换的。
image.png
如果再继续说下去就有点蒙圈了. 还是按照简单易懂的说法吧:
看这里,你可以想象成Binder Driver就是一个管道,ServerManager是一个注册表,所有的Binder Client和Binder Server都要在它那里注册,Binder Client也通过ServerManager去查找对应的Binder Server
最后,Binder Client和Binder Server其实实现的接口是一样的,所以大家可以联想到Binder机制其实也是一种代理模式.
总结
代理模式是一种使用比较多的一种结构性设计模式,这节通过一个通用模式代码讲解了代理模式的基本实现方案,然后又引入了一个小民打官司的栗子,讲解了如何去实现静态代理和动态代理,然后深入了解了动态代理的实现原理和用处,最后讲解了Android中有哪些地方用到了代理模式实现.