美文网首页
Android源码设计模式学习笔记-代理模式

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

作者: e小e | 来源:发表于2018-02-16 15:54 被阅读20次

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


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

    相关文章

      网友评论

          本文标题:Android源码设计模式学习笔记-代理模式

          本文链接:https://www.haomeiwen.com/subject/etlutftx.html