Android源码设计模式学习笔记-代理模式

2018-02-16  本文已影响20人  e小e

代理模式也称为委托模式,其实代理在我们日常生活中并不少见,对于程序员来说最常接触的莫过于代理上网了,代理模式在开发过程使用非常普遍.


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实现在用户空间中.

image.png
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中有哪些地方用到了代理模式实现.

上一篇下一篇

猜你喜欢

热点阅读