設計模式(七)Android中的代理模式

猥瑣發育_別浪發表於2019-03-19

一、相關概念

1、定義

為其他物件提供一種代理以控制對這個物件的訪問

2、使用場景

主要作用:控制物件訪問

  • 擴充套件目標物件的功能:例如演員(目標物件),有演戲的功能,找一個經紀人(代理),會額外提供收費的功能,實際上是代理的功能,而不是演員的功能。
  • 限制目標物件的功能:例如經紀人對收費不滿意,只讓演員演一場戲,對演員的功能進行了部分限制。

3、類圖

設計模式(七)Android中的代理模式

  • 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模型

設計模式(七)Android中的代理模式

  • 包括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方法執行時,進行控制並執行自己的相應邏輯

相關文章