Retrofit 源码剖析-深入

Posted wzgiceman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit 源码剖析-深入相关的知识,希望对你有一定的参考价值。

背景

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

Retrofit源码解析-动态代理

思路

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

RxRetrofit-专栏

项目分析

想要弄清楚 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()方法进入源码

   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群告诉我!

以上是关于Retrofit 源码剖析-深入的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码剖析1:初探Spring IOC核心流程

Android开发:深入源码剖析图片加载过程,面试官再也不能为难我了!

深入剖析 RocketMQ 源码 - 负载均衡机制

深入剖析 RocketMQ 源码 - 负载均衡机制

带你一步步剖析Retrofit 源码解析:一款基于 OkHttp 实现的网络请求框架

这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)(转)