代理设计模式-从Retrofit的create方法分析动态代理

代理在生活中非常常见,如我们平时买东西,我们不会去工厂买,而是去超市或者网购。超市和网购平台实际上就是一种代理,他们代理了我们去向工厂或者向中间商购买和运输的过程。这是生活中的代理,那么我们开发中的代理模式是怎样的呢?

代理模式

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

涉及角色及说明
Subject(抽象主题类):接口或抽象类,声明真实主题与代理的共同接口方法。
RealSubject(真实主题类):也被叫做代理类或被委托类,定义了代理所表示的真实对象,负责具体业务逻辑的执行,客户端可以通过代理类间接的调用真实主题类的方法。
Proxy(代理类):也叫委托类,持有对真实主题的引用,在其所实现的接口中调用真实主题类中相应的接口方法执行。
Client(客户端类):使用代理模式的地方

以日常购买东西为例子,消费者只需要关心购买东西(静态代理)

抽象主题类
定义了真实主题与代理的共同接口方法

public interface IBuy {
    void buy();
}

真实主题类
消费者只关心买东西

public class Consumer implements IBuy {
    @Override
    public void buy() {
        System.out.println("消费者买东西");
    }
}

代理类
持有真实主题类的引用,为真实主题类提供额外服务

public class Supermarket implements IBuy {
    private IBuy consumer;

    public Supermarket(IBuy consumer) {
        this.consumer = consumer;
    }

    @Override
    public void buy() {
        System.out.println("从工厂买回来");
        consumer.buy();
        System.out.println("提供售后服务");
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        Supermarket supermarket = new Supermarket(consumer);
        supermarket.buy();
    }
}

输出结果:

从工厂买回来
消费者买东西
提供售后服务

小结一下
静态代理的代理类在编译时期已经存在,一般需要先定义接口,被代理对象和代理对象共同实现这个接口
优点:
1.职责清晰,被代理角色只实现实际的业务逻辑,代理对象实现附加的处理逻辑
2.扩展性高,可以更换不同的代理类,实现不同的代理逻辑
缺点也比较明显
如果代理的业务类型增加,需要新增接口方法,同时代理类和被代理类都需要对应的去新增方法。如果新增的业务量非常多,那么代理类的代码将会暴增,可读性降低难以维护。

同样以日常购买东西为例子(动态代理

代理类

public class BuyInvocationHandler implements InvocationHandler {
    private IBuy mConsumer;

    public BuyInvocationHandler(IBuy mConsumer) {
        this.mConsumer = mConsumer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("从工厂买回来");
        Object returnObject = method.invoke(mConsumer, args);
        System.out.println("提供售后服务");
        return returnObject;
    }
}

真实主题类

public class Consumer implements IBuy {
    @Override
    public void buy() {
        System.out.println("消费者买东西");
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        IBuy consumerBuy = (IBuy) Proxy.newProxyInstance(consumer.getClass().getClassLoader(), consumer.getClass().getInterfaces(),
                new BuyInvocationHandler(consumer));
        consumerBuy.buy();
    }
}

输出结果:

从工厂买回来
消费者买东西
提供售后服务

小结一下
动态代理是指运行时动态生成一个代理对象,相对于编译时的静态来区分。动态代理可以在运行时动态创建一个类,实现一个或多个接口,可以在不修改原有类的基础上动态为通过该类获取的对象添加方法、修改行为。
这个动态生成的代理类帮我们做一些逻辑处理,主要是利用字节码技术创建Proxy类然后通过反射创建实例。

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

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

参数说明
*Object proxy:被代理的对象
*Method method:要调用的方法
*Object[] args:方法调用所需要的参数

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

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        Class cl = getProxyClass0(loader, intfs);

        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            final Constructor cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });

                cons.setAccessible(true);
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

参数说明:
*ClassLoader loader:类加载器
*Class[] interfaces:要代理的接口
*InvocationHandler h:实现InvocationHandler接口的子类

生成的代理类大概如下:

public final class $Proxy0 extends Proxy implements IBuy { 
  //这4个Method对象分别代表equals()、toString()、buy()、hashCode()方法 
  private static Method m1; 
  private static Method m2; 
  private static Method m3; 
  private static Method m0; 
  //构造方法接收一个InvocationHandler对象为参数,这个对象就是代理类的“直接委托类”(真正的委托类可以看做代理类的“间接委托类”)
  public $Proxy0(InvocationHandler var1) throws { 
    super(var1); 
  } 
  //对equals方法的调用实际上转为对super.h.invoke方法的调用,父类中的h即为我们在构造方法中传入的InvocationHandler对象,以下的toString()、buy()、hashCode()等方法同理 
  public final boolean equals(Object var1) throws { 
    try { 
      return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); 
    } catch (RuntimeException | Error var3) { 
      throw var3; 
    } catch (Throwable var4) { 
      throw new UndeclaredThrowableException(var4); 
    } 
  } 
  public final String toString() throws { 
    try { 
      return (String)super.h.invoke(this, m2, (Object[])null); 
    } catch (RuntimeException | Error var2) { 
      throw var2; 
    } catch (Throwable var3) { 
      throw new UndeclaredThrowableException(var3); 
    } 
  } 
  public final void buy() throws { 
    try { 
      super.h.invoke(this, m3, (Object[])null); 
    } catch (RuntimeException | Error var2) { 
      throw var2; 
    } catch (Throwable var3) { 
      throw new UndeclaredThrowableException(var3); 
    } 
  } 
  public final int hashCode() throws { 
    try { 
      return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); 
    } catch (RuntimeException | Error var2) { 
      throw var2; 
    } catch (Throwable var3) { 
      throw new UndeclaredThrowableException(var3); 
    } 
  } 
  //这里完成Method对象的初始化(通过反射在运行时获得Method对象) 
  static { 
    try { 
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); 
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); 
      m3 = Class.forName("Sell").getMethod("sell", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); 
    } catch (NoSuchMethodException var2) { 
      throw new NoSuchMethodError(var2.getMessage()); 
    } catch (ClassNotFoundException var3) { 
      throw new NoClassDefFoundError(var3.getMessage()); 
    } 
  }
}

Retrofit的代理模式
基本使用:
(1).定义接口

public interface GitHubService {
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

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

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);

(3).由创建的GitHubService的向web服务器发出同步或异步HTTP请求

Call> repos = service.listRepos("octocat");

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

public  T create(final Class service) {
    validateServiceInterface(service);//1
    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 @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);//2
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);//3
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);//4
          }
        });
}

注释分析
*1.判断是否是一个接口
*2.判断调用的方法是否属于Object,如toString,hashCode,属于Object执行
*3.判断平台是java还是Android,Android不会进
*4.解析接口的方法、注解、参数并执行方法(这里是Retrofit重点方法,代码细节超出本文主题范围,将在Retrofit源码分析重点探讨)

Retrofit为什么要这样设计?
个人认为主要有两点
*1.应用的请求接口可能有很多个,通过代理模式,能动态的为每个接口生成具体的代理类,并实现了我们的接口,我们不需要关心具体的细节,我们只需要声明接口然后传递给Retrofit即可,然后有Retrofit动态生成具体请求对象,发起请求并把结果返回给我们。
*2.让开发者与Retrofit的底层实现okhttp完全解耦,哪怕作者后期决定底层实现不再采用okhttp,开发者的代码依然不需要改变

你可能感兴趣的:(代理设计模式-从Retrofit的create方法分析动态代理)