Android--代理模式和Retrofit源码浅析

一、代理模式

因为Retrofit用到了动态代理模式,所以先说说代理模式。

1、代理模式的定义

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

代理模式角色分为 3 种:

Subject(抽象主题角色) :定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;

RealSubject(真实主题角色):真正实现业务逻辑的类;

Proxy(代理主题角色) :用来代理和封装真实主题;

代理模式的结构比较简单,其核心是代理类,为了让客户端能够一致性地对待真实对象和代理对象,在代理模式中引入了抽象层。

如果根据字节码的创建时机来分类,可以分为静态代理和动态代理:

  • 所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和真实主题角色的关系在运行前就确定了。
  • 而动态代理的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以在运行前并不存在代理类的字节码文件

2、静态代理模式

先看下面四段代码:

定义一个接口

interface UserInfoChangeListener {

    void onChange();
}

 接口的实现类

public class UserInfoChangeImpl implements UserInfoChangeListener{
    @Override
    public void onChange() {
        LogUtil.d("实现类打印:用户信息已变更");
    }
}

代理类

/**
 * 静态代理的实现类
 * 静态代理是一个提前定义好的类文件,会被编译为字节码文件,代理关系已经在类中确定好了
 */
public class UserInfoChangeProxyImpl implements UserInfoChangeListener {

    //静态代理要点之一:代理类会持有被代理类的引用,这里代理的是接口或者说其实是接口的实现类
    private UserInfoChangeListener mUserInfoChangeListener;

    //构造方法,传入引用
    public UserInfoChangeProxyImpl(UserInfoChangeListener userInfoChangeListener){
        mUserInfoChangeListener = userInfoChangeListener;
    }

    @Override
    public void onChange() {
        //可以通过引用调用实现方法,也可以重写,可以修改,做权限控制等等
        mUserInfoChangeListener.onChange();
        LogUtil.d("代理类打印:代理类添加打印信息");

    }
}

测试代码

UserInfoChangeListener listener = new UserInfoChangeImpl();
UserInfoChangeListener proxy = new UserInfoChangeProxyImpl(listener);
proxy.onChange();

打印结果

com.abc.testretrofit D/SHOW_LOG: │ 实现类打印:用户信息已变更
com.abc.testretrofit D/SHOW_LOG: │ 代理类打印:代理类添加打印信息

静态代理类的用法比较简单,如上。

静态代理模式的缺点:

虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。

1、 当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:

  • 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
  • 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类

2、 当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护

3、动态代理模式

1)为什么类可以动态生成?

Java虚拟机类加载过程主要分为五个阶段:加载、验证、准备、解析、初始化。其中加载阶段需要完成以下3件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  3. 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据访问入口

由于虚拟机规范对这3点要求并不具体,所以实际的实现是非常灵活的,关于第1点,获取类的二进制字节流(class字节码)就有很多途径:

  • 从ZIP包获取,这是JAR、EAR、WAR等格式的基础
  • 从网络中获取,典型的应用是 Applet
  • 运行时计算生成,这种场景使用最多的是动态代理技术,在 java.lang.reflect.Proxy 类中,就是用了 ProxyGenerator.generateProxyClass 来为特定接口生成形式为 *$Proxy 的代理类的二进制字节流
  • 由其它文件生成,典型应用是JSP,即由JSP文件生成对应的Class类
  • 从数据库中获取等等

所以,动态代理就是想办法,根据接口或目标对象,计算出代理类的字节码,然后再加载到JVM中使用。但是如何计算?如何生成?情况也许比想象的复杂得多,我们需要借助现有的方案。

2)动态代理图示

这个就是动态代理的大概类图结构,其中Subject 、ProxySubject、 RealSubject和Client角色的作用和静态代理的一样,这里就不在累述,与静态代理相比,多了一个InvocationHandler角色和一个Proxy角色,InvocationHandler是java提供的一个接口,我们需要定义一个类实现InvocationHandler接口,这里就叫DynamicProxy角色;Proxy是java提供用于动态生成ProxySubject的一个类,它需要ProxySubject继承。

我们看到DynamicProxy在ProxySubject和RealSubject之前起到了中间人的角色,ProxySubject会把事情委托给DynamicProxy来做,而DynamicProxy最终把事情委托给RealSubject来做,可以这样说:ProxySubject代理了DynamicProxy,而DynamicProxy代理了RealSubject,其中最重要的一点是ProxySubject是在代码运行时才动态生成的,这是和静态代理的最大区别。

接下来简单介绍一下InvocationHandler接口,Proxy类。

3)InvocationHandler和Proxy的作用

为了让我们更加容易的实现动态代理,java提供了动态代理接口InvocationHandler和动态代理类Proxy供我们使用,它们都在java.lang.reflect包中,可见动态代理和反射有不可逃脱的关系。

InvocationHandler接口 定义如下:

public interface InvocationHandler {
  /**
   * 这个方法的含义是:代理对象proxy要调用真实对象的method
   * @param proxy 代理对象
   * @param method 真实对象被调用的方法
   * @param args 被调用的方法的参数
   */
  Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

InvocationHandler接口的作用就是在invoke方法中执行真实对象的方法,可以看到里面只有一个invoke方法,我们需要为真实对象定义一个实现了这个接口中的invoke方法的动态代理类,同时在创建这个动态代理类的实例的时候,我们还要在方法或构造中传入真实对象的引用,即InvocationHandler的实现类需要持有真实对象的引用,这样才能执行真实对象的方法

Proxy类定义如下:

public class Proxy implements Serializable {
    
    protected InvocationHandler h;//持有一个InvocationHandler类型的引用

    protected Proxy(InvocationHandler h) {
        this.h = h;
    }

    //根据指定的类加载器和接口来获取代理对象的Class对象
    public static Class<?> getProxyClass(ClassLoader loader, Class... interfaces) throws IllegalArgumentException {
        //...
    }

    //根据指定的类加载器和接口生成代理对象
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
        //...
    }
    
    //...
}

Proxy这个类的作用就是用来动态的创建一个代理对象,它内部会持有一个InvocationHandler引用,在构造中传入,它提供了许多的方法,但是我们常用的是 getProxyClass方法和newProxyInstance方法:

  • getProxyClass(重点方法):这个方法的作用是在运行时根据.class的结构生成一个代理Class二进制流,并通过传入的ClassLoader去把代理Class二进制流加载成一个代理Class对象,该代理Class对象继承Proxy并实现了传入的第二个参数对应的Interface列表。
  • newProxyInstance(常使用的方法): 这个方法的作用是在运行时根据代理Class对象生成代理对象实例,这个方法中会先调用了getProxyClass方法生成代理Class对象,在获取到代理Class对象后,根据第三个参数InvocationHandler引用通过反射创建代理对象实例,所以newProxyInstance最终的结果是生成一个代理对象实例,该代理对象会继承Proxy类并实现给定的接口列表,同时内部持有一个InvocationHandler引用。

4)动态代理的使用步骤

使用动态代理的基本步骤如下:

1、定义代理对象和真实对象的公共接口;(与静态代理步骤相同)

2、真实对象实现公共接口中的方法;(与静态代理步骤相同)

3、定义一个实现了InvocationHandler接口的动态代理类;

4、通过Proxy类的newProxyInstance方法创建代理对象,调用代理对象的方法。

1和2步骤都是和静态代理步骤相同的,就不在累述了,和静态代理相比,少了的一个步骤是:代理对象实现公共接口的方法,因为前面讲过代理对象是代码运行时通过Proxy动态创建的,所以不需要提前编写代理对象的类;和静态代理相比,多了的两个步骤是:3、定义一个实现了InvocationHandler接口的动态代理类和4、通过Proxy类的newProxyInstance方法创建代理对象,调用代理对象的方法。

5)动态代理示例

看如下代码:
定义一个接口

interface UserInfoChangeListener {

    void onChange();
}

接口的实现类

public class UserInfoChangeImpl implements UserInfoChangeListener{
    @Override
    public void onChange() {
        LogUtil.d("实现类打印:用户信息已变更");
    }
}

定义代理规则实现InvocationHandler接口

public class DynamicProxyHandler implements InvocationHandler {

    private Object mObject;//真实对象的引用

    public DynamicProxyHandler(Object object){
        this.mObject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过反射调用真实对象的方法
        Object result = method.invoke(mObject, args);
        return result;
    }
}

测试代码调用

//接口实例
UserInfoChangeListener listener = new UserInfoChangeImpl();
//构造一个动态代理
InvocationHandler invocationHandler = new DynamicProxyHandler(listener);
//获取接口实例的类加载器
ClassLoader classLoader = listener.getClass().getClassLoader();
//通过Proxy类的newProxyInstance方法动态构造一个代理类对象
UserInfoChangeListener proxy = (UserInfoChangeListener) Proxy.newProxyInstance(classLoader, new Class[]{UserInfoChangeListener.class}, invocationHandler);
//调用代理对象的方法
proxy.onChange();

二、Retrofit源码浅析

以Retrofit入口代码开始:

client = new OkHttpClient.Builder()
        //添加log拦截器
        //.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) //okhttp默认的
        .addInterceptor(new HttpLoggingInterceptor(new HttpLogger()).setLevel(HttpLoggingInterceptor.Level.BODY))
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
        .build();

retrofit = new Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addConverterFactory(ScalarsConverterFactory.create())
        //支持RxJava
        .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
        .client(client)
        .build();

apiServer = retrofit.create(ApiServer.class);

1、Retrofit 的 create 方法

public <T> T create(final Class<T> service) {
  //验证传入的service是否是一个接口,并且不能是泛型
  validateServiceInterface(service);
  //动态代理的方法,返回定义的service的实例
  return (T)
      Proxy.newProxyInstance(
          //获取类的类加载器
          service.getClassLoader(),
          //传入service的字节码对象到数组
          new Class<?>[] {service},
          //传入接口对象,重写invoke方法
          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 the method is a method from Object then defer to normal invocation.
              //代理类的生成默认会继承bject,调用代理类的方法
              if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
              }
              args = args != null ? args : emptyArgs;
              //如果是默认方法(比如 Java8 ),就执行 platform 的默认方法。否则执行`loadServiceMethod`方法的`invoke`方法
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

2、loadServiceMethod方法

我们先看loadServiceMethod方法返回的是什么对象,然后再看这个对象的 invoke 方法。

//serviceMethodCache是一个Map集合,将service中的方法存起来
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

ServiceMethod<?> loadServiceMethod(Method method) {
  //如果方法存在就从集合里面取
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;

  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
     //创建一个 ServiceMethod 对象
      result = ServiceMethod.parseAnnotations(this, method);
     //用 Map 把创建的 ServiceMethod 对象缓存起来,因为我们的请求方法可能会调用多次,缓存提升性能。
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

看一下 ServiceMethod.parseAnnotations(this, method);方法具体返回的对象是什么,然后再看它的 invoke 方法。

3、ServiceMethod的parseAnnotations方法

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //建造者模式构建一个RequestFactory对象
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

  Type returnType = method.getGenericReturnType();
  if (Utils.hasUnresolvableType(returnType)) {
    throw methodError(
        method,
        "Method return type must not include a type variable or wildcard: %s",
        returnType);
  }
  if (returnType == void.class) {
    throw methodError(method, "Service methods cannot return void.");
  }
 
  //返回一个HttpServiceMethod对象
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

4、HttpServiceMethod类的invoke 方法

@Override
final @Nullable ReturnT invoke(Object[] args) {
  //创建call对象,okhttpCall
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  //调用的是子类 CallAdapted 的 `adapt`
  return adapt(call, args);
}

5、OkHttpCall的enqueue方法

这段代码比较长,但这个就是这个请求的关键,以及怎么使用 OkHttp 进行请求的,如果解析 Response 的,如何回调的。

@Override
public void enqueue(final Callback<T> callback) {
  Objects.requireNonNull(callback, "callback == null");
  //声明一个 okhttp3.Call 对象,用来进行网络请求
  okhttp3.Call call;
  Throwable failure;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;
    call = rawCall;
    failure = creationFailure;
    if (call == null && failure == null) {
      try {
       //给 okhttp3.Call 对象进行赋值
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }
  //进行真正的网络请求
  call.enqueue(
      new okhttp3.Callback() {
        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
          Response<T> response;
          try {
           //解析响应
            response = parseResponse(rawResponse);
          } catch (Throwable e) {
            throwIfFatal(e);
            callFailure(e);
            return;
          }

          try {
           //成功的回调
            callback.onResponse(OkHttpCall.this, response);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }

        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
          callFailure(e);
        }

        private void callFailure(Throwable e) {
          try {
            callback.onFailure(OkHttpCall.this, e);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }
      });
}

6、okhttp3.Call 对象是怎么创建的

看下 call = rawCall = createRawCall();方法

private okhttp3.Call createRawCall() throws IOException {
  okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

通过 callFactory 创建的,而callFactoryOkHttpCall构造方法传入的,看下OkHttpCall的创建过程

//HttpServiceMethod.java
private final okhttp3.Call.Factory callFactory;

@Override
final @Nullable ReturnT invoke(Object[] args) {
  //在 OkHttpCall 实例化时赋值, callFactory 是 HttpServiceMethod 的成员变量
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

//callFactory 是在 HttpServiceMethod 的构造中赋值的
HttpServiceMethod(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory, 
    Converter<ResponseBody, ResponseT> responseConverter) { 
    this.requestFactory = requestFactory; 
    //通过 HttpServiceMethod 构造直接赋值
    this.callFactory = callFactory;
    this.responseConverter = responseConverter; }

7、HttpServiceMethod是怎么创建的

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
  boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
  boolean continuationWantsResponse = false;
  boolean continuationBodyNullable = false;

 ...略...

  //callFactory 的值是从 Retrofit 这个对象拿到的
  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  //如果不是协程的挂起函数,返回CallAdapted对象
  if (!isKotlinSuspendFunction) {
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } else if (continuationWantsResponse) {
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForResponse<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
  } else {
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForBody<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
            continuationBodyNullable);
  }
}

继续看retrofit.callFactory

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    //callFactory本质就是OkHttpClient对象
    callFactory = new OkHttpClient();
  }

 ...略...

  return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);
}

猜你喜欢

转载自blog.csdn.net/weixin_53545232/article/details/124872581