Retrofit 源码剖析-深刻

背景

前一章节,先系统的讲解了关于Retrofit实现当中的主要技术动态代理,本篇详细结合动态代理在Retrofit中的应用,扩展到结合RxJava来使用html

Retrofit源码解析-动态代理java

思路

要深刻研究一款开源项目最好的入口就是它所暴露出来的外部使用接口,按照这个思路,因此须要大致先了解Retrofit的基本使用,这里就不阐述这些基础的知识,能够查看之前的博客git

RxRetrofit-专栏github

项目分析

想要弄清楚 Retrofit 的细节,先来看一下 Retrofit 源码的组成:设计模式

这里写图片描述

  • 一个 retrofit2.http 包,里面所有是定义 HTTP 请求的注解,好比 GET、POST、PUT、DELETE、Headers、Path、Query 等等数组

  • 余下的 retrofit 2.0 包中十几个类和接口就是所有 retrofit 的代码了,代码真的不多,很简单,由于retrofit把网络请求这部分功能所有交给了 okHttp 了缓存

初始对象

先上一段使用Retrofit开始前的初始代码网络

//手动建立一个OkHttpClient并设置超时时间缓存等设置
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);

        /*建立retrofit对象*/
        Retrofit retrofit = new Retrofit.Builder()
                .client(builder.build())
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(basePar.getBaseUrl())
                .build();复制代码

这里的入口Builder()方法进入源码ide

public static final class Builder {
    private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
    }

    public Builder() {
      this(Platform.get());
    }
xxxx复制代码

Builder类中主要是记录请求过程当中的一些配置信息,好比基础url,固然重要的是addConverterFactory方法记录Converter数据转换器;addCallAdapterFactory方法记录CallAdapter-HTTP请求返回数据的类型.工具

Converter数据转换器

Converter数据转换器默认存放在retrofit-converters

这里写图片描述

Converter采用接口抽象的方式,灵活了转换器的种类,经常使用的如上图中的GsonString,一样这里能够能够自由扩展,实现Converter.Factory接口

CallAdapter请求返回数据的类型

工程位置如图

这里写图片描述

这里同Converter数据转换器思想同样一样是采用抽象接口的方式,继承CallAdapter.Factory类实现扩展,正如上图中箭头指示的显示扩展的RxJava2的扩展

信息的转换

Builder记录完数据后经过build()方法,将收集的信息传递给最后的Retrofit对象中,而且初始了okhttp3.Call.Factory请求处理类,从中能够看出Retrofit2.0底层的http请求默认就是经过okhttp3处理的。

/** * Create the {@link Retrofit} instance using the configured values. * <p> * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */
    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }复制代码

动态代理

Retrofit初始完成之后,须要调用create方法传入一个java接口抽象类对象做为参数。其实这一步真是Retrofit动态代理生成的地方

源码:

@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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, 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 serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }复制代码

使用代码:

HttpTestService httpService = retrofit.create(HttpTestService.class);
        httpService.getAllVedioBy(isAll());复制代码

上面HttpTestService对象实际上是一个动态代理对象,并非一个真正的 HttpTestService接口的implements对象,当 httpService对象调用 getAllVedioBy方法时,执行的是下面动态代理方法。

ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);复制代码

其中主要ServiceMethod是主要的处理对象

ServiceMethod信息类

当调用loadServiceMethod方法,将抽象HttpTestService中经过注解定义的信息收集起来存放于ServiceMethod中,其中主要包含了一下数据:

  • OkHttpClient:发送网络请求的工具

  • RequestFactory: 相似于 Volley 中的 Request,包含了HTTP请求的Url、Header信息,MediaType、Method以及RequestAction数组

  • CallAdapter:HTTP请求返回数据的类型

  • Converter:数据转换器

最后Map<Method, ServiceMethod> serviceMethodCache保存所有的 ServiceMethod信息类

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }复制代码

debug可查看当前ServiceMethod对象收集的信息

这里写图片描述

收集完信息之后执行了

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);复制代码

这一步对okhttp熟悉的同窗确定知道了,就是经过okhttp请求数据,其中serviceMethod是请求的地址信息,args是当前接口须要的参数信息。

执行完http请求之后,执行了

serviceMethod.callAdapter.adapt(okHttpCall);复制代码

这一步是将okhttp获取到的数据传递给一开始Retrofit经过builder指定的RxJavaCallAdapterFactory类,那它是如何一步步处理的呢?

其实在一开始的获取serviceMethod方法loadServiceMethod(Method method)中,已经将Retrofit对象传递给了serviceMethod对象

核心代码:

//这里的this便是`Retrofit`对象
result = new ServiceMethod.Builder(this, method).build();复制代码

经过.Builder(this, method).build()方法将Retrofit一开始的builder信息所有传递给了如今的serviceMethod对象,因此当执行

serviceMethod.callAdapter.adapt(okHttpCall);复制代码

serviceMethod.callAdapter便制动转换成了RxJavaCallAdapterFactory,调用CallAdapter抽象接口adapt进入到RxJavaCallAdapterFactory类中

源码:

@Override public <R> Observable<Response<R>> adapt(Call<R> call) {
      Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));
      if (scheduler != null) {
        return observable.subscribeOn(scheduler);
      }
      return observable;
    }
  }复制代码

最后生成RxJavaObservable对象,后面经过获得的Observable对象就是对数据的处理了。

到此基于Retrofit结合RxJava源码的解读就完成了,回头看整个过程其实仍是很简单,做者条理清晰理解起来也很简单,一口气终于把Retrofit大致撸了一遍。

总结

Retrofit 很是巧妙的用注解来描述一个 HTTP 请求,将一个 HTTP 请求抽象成一个 Java 接口,而后用了 Java 动态代理的方式,动态的将这个接口的注解“翻译”成一个 HTTP 请求,最后再执行这个 HTTP 请求

Retrofit的功能很是多的依赖 Java 反射,代码中其实还有不少细节,好比异常的捕获、抛出和处理,大量的 Factory 设计模式。

Retrofit 中接口设计的恰到好处,在你建立 Retrofit 对象时,让你有更多更灵活的方式去处理你的需求,好比使用不一样的 Converter、使用不一样的 CallAdapter,这也就提供了你使用 RxJava 来调用 Retrofit 的可能。

专栏

RxJava+Retrofit+OkHttp深刻浅出-终极封装专栏)

源码

retrofit2.0

建议

若是你有任何的问题和建议欢迎加入QQ群告诉我!

相关文章
相关标签/搜索