设计模式(九)Android中的代理模式

4,173 阅读6分钟

一、相关概念

1、定义

为其他对象提供一种代理以控制对这个对象的访问

2、使用场景

主要作用:控制对象访问

  • 扩展目标对象的功能:例如演员(目标对象),有演戏的功能,找一个经纪人(代理),会额外提供收费的功能,实际上是代理的功能,而不是演员的功能。
  • 限制目标对象的功能:例如经纪人对收费不满意,只让演员演一场戏,对演员的功能进行了部分限制。

3、类图

  • Subject:抽象主题角色,主要是声明代理类和被代理类共同的接口方法
  • RealSubject:具体主题角色(被代理角色),执行具体的业务逻辑
  • Proxy:代理类,持有一个被代理对象的引用,负责在被代理对象方法调用的前后做一些额外操作

4、优点

  • 职责清晰,被代理角色只实现实际的业务逻辑,代理对象实现附加的处理逻辑
  • 扩展性高,可以更换不同的代理类,实现不同的代理逻辑

二、静态代理:

编译时期就已经存在,一般首先需要定义接口,而被代理的对象和代理对象一起实现相同的接口。

1、接口定义:

public interface Play {
  //唱歌
  void sing(int count);
  //演出
  void show();
}

2、演员(被代理对象):

public class Actor implements Play {
  @Override
  public void sing(int count) {
    System.out.print("唱了" + count + "首歌");
  }

  @Override
  public void show() {
    System.out.print("进行演出");
  }
}

被代理对象提供了几个具体方法实现

3、经纪人(代理对象):

public class Agent implements Play {
  //被代理对象
  private Play player;
  private long money;

  public void setMoney(long money){
    this.money = money;
  }

  /**
   * @param player
   * @param money 收费
   */
  public Agent(Play player, long money) {
    this.player = player;
    this.money = money;
  }

  @Override
  public void sing(int count) {
    player.sing(count);
  }
  //控制了被代理对象的访问
  @Override
  public void show() {
    if (money > 100) {
      player.show();
    } else {
      System.out.println("baibai...");
    }
  }
}  

4、使用

public class PlayTest {
  public static void main(String[] args){
    Actor actor = new Actor();
    Agent agent = new Agent(actor, 50);
    agent.sing(2);
    agent.show();
    agent.setMoney(200);
    agent.show();
  }
}

代理对象通过自身的逻辑处理对目标对象的功能进行控制。

三、动态代理:

动态一般指的是在运行时的状态,是相对编译时的静态来区分,就是在运行时生成一个代理对象帮我们做一些逻辑处理。主要使用反射技术获得类的加载器并且创建实例。
动态代理可以在运行时动态创建一个类,实现一个或多个接口,可以在不修改原有类的基础上动态为通过该类获取的对象添加方法、修改行为。

1、生成动态代理类:

InvocationHandler是动态代理接口,动态代理类需要实现该接口,并在invoke方法中对代理类的方法进行处理

public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable;
}

参数说明:

  • Object proxy:被代理的对象
  • Object[] args:要调用的方法
  • Object[] args:方法调用所需要的参数

2、创建动态代理类

Proxy类可以通过newProxyInstance创建一个代理对象

#Proxy
public static Object newProxyInstance(ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h)
    throws IllegalArgumentException {
  if (h == null) {
    throw new NullPointerException();
  }  
  Class<?> cl = getProxyClass0(loader, interfaces);
  try {
    //通过反射完成了代理对象的创建
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    return newInstance(cons, h);
  } catch (NoSuchMethodException e) {
    throw new InternalError(e.toString());
  }
}

参数说明:

  • ClassLoader loader:类加载器
  • Class<?>[] interfaces:所有的接口
  • InvocationHandler h:实现InvocationHandler接口的子类

3、动态代理demo:

(1)定义动态代理类

public class ActorProxy implements InvocationHandler {
  private Play player;
  public ActorProxy(Play player){
    this.player = player;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //处理被代理对象的方法实现
    if ("show".equals(method.getName())){
      System.out.println("代理处理show....");
      return method.invoke(player, null);
    }else if ("sing".equals(method.getName())){
      System.out.println("代理处理sing....");
      return method.invoke(player, 2);
    }
    return null;
  }
} 

代理类实现InvocationHandler接口,在invoke方法中对player(被代理对象)做相应的逻辑处理。

(2)使用

public class ProxyTest {

  public static void main(String[] args) {
    Play actor = new Actor();
    //通过调用Proxy.newProxyInstance方法生成代理对象
    Play proxy = (Play) Proxy.newProxyInstance(actor.getClass().getClassLoader()
        , actor.getClass().getInterfaces(), new ActorProxy(actor));
    //调用代理类相关方法
    proxy.show();
    proxy.sing(3);
  }
}

四、Android中的代理模式

1、Retrofit代理模式

(1)Retrofit使用:
定义接口

public interface MyService {
    @GET("users/{user}/list")
    Call<String> getMyList(@Path("user") String user);
}

新建retrofit对象,然后产生一个接口对象,然后调用具体方法去完成请求。

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://xxx.com")
            .build();
MyService myService = retrofit.create(MyService.class);
Call<String> myList = myService.getMyList("my");

retrofit.create方法就是通过动态代理的方式传入一个接口,返回了一个对象

(2)动态代理分析:

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();
        private final Object[] emptyArgs = new Object[0];

        @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
          return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        }
      });
}

通过Proxy.newProxyInstance,该动态代理对象可以拿到请求接口实例上所有注解,然后通过代理对象进行网络请求。

2、Binder中的代理模式

Binder机制

远程代理:为某个对象在不同的内存地址空间提供局部的代理对象

(1)AMS、ApplicationThread

  • Activity启动时,应用进程通过本地代理对象IActivityManager,实现了跟SystemServer进程中的ActivityManagerService通信。
  • 当AMS完成对权限、堆栈等信息处理后,通过代理对象IApplicationThread,就可以调用到应用进程(被代理对象)ApplicationThread的方法。

(2)Binder模型

  • 包括Client、Server、ServiceManager、Binder 驱动。
  • 其中Client、Server、Service Manager运行在用户空间,Binder驱动运行在内核空间。
  • 对于Client,Binder是Server本地对象的一个引用,这个引用实际上是一个代理对象,Client通过这个代理对象来间接访问Server的本地对象。
  • 对于Server,Binder是提供具体实现的本地对象,需向ServiceManager注册。
  • Binder驱动是连接Client来Server的桥梁,负责将代理对象转化为本地对象,并将Server的执行结果返回给Client。
  • ServiceManager它保存了Server Binder字符名称和Binder引用的映射,Client通过它来找到Server的Binder引用。

3、插件化中的代理模式

在插件化中,例如VirtualApk,hook住AMS的本地代理对象IActivityManager,相当于IActivityManager的一个代理,控制了IActivityManager的某些行为

(1)创建动态代理

protected void hookSystemServices() {
  try {
    Singleton<IActivityManager> defaultSingleton;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get();
    } else {
      defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get();
    }
    IActivityManager origin = defaultSingleton.get();
    //创建动态代理对象ActivityManagerProxy
    IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClassLoader(), new Class[] { IActivityManager.class },
        createActivityManagerProxy(origin));

    // 通过反射Hook住了IActivityManager
 Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);

    if (defaultSingleton.get() == activityManagerProxy) {
      this.mActivityManager = activityManagerProxy;
      Log.d(TAG, "hookSystemServices succeed : " + mActivityManager);
    }
  } catch (Exception e) {
    Log.w(TAG, e);
  }
}

protected ActivityManagerProxy createActivityManagerProxy(IActivityManager origin) throws Exception {
  return new ActivityManagerProxy(this, origin);
}

创建动态代理ActivityManagerProxy,并通过反射对IActivityManager进行hook

(2)动态代理对象

public class ActivityManagerProxy implements InvocationHandler {
  ......
  //被代理对象
  private IActivityManager mActivityManager;

  public ActivityManagerProxy(PluginManager pluginManager, IActivityManager activityManager) {
    this.mPluginManager = pluginManager;
    this.mActivityManager = activityManager;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //通过监听被代理对象的某些方法,执行自己的相关逻辑
    if ("startService".equals(method.getName())) {
      try {
        return startService(proxy, method, args);
      } catch (Throwable e) {
        Log.e(TAG, "Start service error", e);
      }
    }
    ......
  }
}

ActivityManagerProxy实现InvocationHandler,并持有了IActivityManager,在IActivityManager方法执行时,进行控制并执行自己的相应逻辑

汇总:设计模式总结