Retrofit2源码分析

Retrofit2源码分析

Retrofit是一个基于okhttp的网络请求工具,和google的volley相似,但是更加简洁,可以简洁到调用一个Java方法的方式去请求一个api.

一、如何使用?

通过一个登录接口来看下retrofit是如何使用的,首先配置app级别的gradle依赖,这里涉及json数据转换,所以需要添加适配:converter-gson

依赖如下:

  compile 'com.squareup.retrofit2:retrofit:2.3.0'
  compile 'com.squareup.retrofit2:converter-gson:2.3.0'

然后创建一个Api接口类

// Api.java
public interface Api {

  @POST("login")
  Call<ResponseBody> login(@Body LoginReq req);
}
// 初始化retrofit
Retrofit retrofit = new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
        .baseUrl("http://10.5.16.237:8080/DemoApi/").build();
// 动态代理得到Api实例
Api api = retrofit.create(Api.class);
// 调用登录接口
api.login(new LoginReq("chengyuan", "12345")).enqueue(new retrofit2.Callback<ResponseBody>() {
      @Override public void onResponse(retrofit2.Call<ResponseBody> call,
          retrofit2.Response<ResponseBody> response) {
        try {
          System.out.println("retrofit->" + response.body().string());
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      @Override public void onFailure(retrofit2.Call<ResponseBody> call, Throwable t) {

      }
    });

假设以上代码是通过点击登录按钮来调用的,运行一下:

05-25 11:10:33.676 8540-8540/com.okhttp.okhttp I/System.out: retrofit->"login success"

详细用法查看官网:http://square.github.io/retrofit/

当然,这不是重点,接下来我们看下retrofit是什么实现的?

二、源码分析

看源码之前,我们可以先问自己几个问题,带着问题看源码往往效率更高。

问题一:retrofit是对okhttp的封装,那retrofit是如何一步一步完成对okhttp接口调用的?

先看下retrofit对象是如何构建出来的?

Retrofit retrofit = new Retrofit.Builder()
        .addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://10.4.33.125:8080/DemoApi/").build();

可以看到,构建retrofit传入了baseUrl,并且添加了一个GsonConverterFactory,然后执行build方法,接下来看下build做了哪些事情?

    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);
    }

callFactory默认是一个OkHttpClient,okhttp的Call实例可以猜测是callFactory生成的。然后可以看到通过platform.defaultCallbackExecutor()生成一个callbackExecutor对象,跟踪platform后发现

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

defaultCallbackExecutor实际上是new MainThreadExecutor(),把runnable发送到主线程消息队列执行,好处就是主线程可以直接访问view控件嘛,我们在使用retrofit的时候发现onResponse回调接口可以直接访问view,猜测和这个callbackExecutor有关。

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

这个coverterFactories存放的是GsonConverterFactory.create(),有了gson,我们可以很方便的把json转成实体类

List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

adapterFactories和coverterFactories类似,不过即使我们在构建retrofit时没有指定,adapterFactories仍然会有个默认值,通过platform.defaultCallAdapterFactory(callbackExecutor)得到,跟踪代码

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

adapterFactories存放的是ExecutorCallAdapterFactory对象,继续查看ExecutorCallAdapterFactory实现

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
  final Executor callbackExecutor;

  ExecutorCallAdapterFactory(Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }
    //省略非关键代码
}

ExecutorCallAdapterFactory继承了CallAdapter.Factory,通过重写get方法来得到CallAdapter实例,CallAdapter是一个接口类,通过adapt来构建Call对象来调用网络接口,这里不是直接调用,而是通过Call的代理类ExecutorCallbackCall来完成,详细查看ExecutorCallbackCall的enqueue接口可以发现,onResponse回调接口是由callbackExecutor发射runnable到主线程处理的,所以可以在onResponse处理view控件,这个也印证了之前的猜测,确实和callbackExecutor有关。

整理一下思路:ExecutorCallAdapterFactory是为了构建CallAdapter从而得到Call实例来调用网络接口;下面我们再找找CallAdapter的adapt什么时候被触发?

    api = retrofit.create(Api.class);

我们看到retrofit调用了create方法,查看create实现,发现用到了动态代理,不清楚动态代理的,可以查看Design pattern–代理模式

  @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, @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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

可以理解为动态生成了代理类$Proxy,我们调用的login接口会代理到InvocationHandler#invoke方法,可以看到invoke的method参数指向我们调用的login接口,重点来了

serviceMethod.callAdapter.adapt(okHttpCall);

我们刚才再想callAdapter的adapt原来是在这里触发的。查看serviceMethod的callAdapter,其实就是从adapterFactories取出来的,我们构建retrofit的时候有保存了一个默认值:platform.defaultCallAdapterFactory(callbackExecutor),serviceMethod.callAdapter指向的是正式ExecutorCallAdapterFactory通过get构建的callAdapter,然后调用adapt接口得到Call实例,Call实例被ExecutorCallbackCall代理。adapt的参数是OkHttpCall,那说明ExecutorCallbackCall代理了OkHttpCall的接口逻辑,最终由OkHttpCall调用okhttp3.Call.

看到这里我们基本上已经把整个调用逻辑分析了一遍,也完成了对问题一的回答。


问题二:为什么要在retrofit初始化的时候动态传入GsonConverterFactory呢?这么设计有什么好处?

看源码前我猜测是为了解耦,同时提高代码灵活性,做到插件式的即插即用吧。

我们还是分析下GsonConverterFactory在源码中是如何使用的?
gson的作用无非方便就是json和实体类之间格式转换,通常我们会在拿到接口返回数据的时候使用gson转成实体类,这里也一样,我们知道调用login接口最终还是通过OkHttpCall调用的okhttp3.Call.enqueue或者execute完成

call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }
      // 省略非关键代码
}

继续跟踪parseResponse发现是通过T body = serviceMethod.toResponse(catchingBody);来转换数据格式的,查看具体实现

  /** Builds a method return value from an HTTP response body. */
  R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

接着看代码

public ServiceMethod build() {
    // 省略非关键代码
    responseConverter = createResponseConverter();
    ...
}

查看完createResponseConverter代码发现,responseConverter是调用保存在converterFactories中的GsonConverterFactory的responseBodyConverter方法得到的。最终由GsonResponseBodyConverter的convert方法完成格式转换

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}

到这里,分析完了GsonConverterFactory在retrofit源码中的使用情况,再看下为什么要这么设计?

好处就是可以根据项目情况灵活使用如下插件

这里写图片描述

retrofit的大部分逻辑都是在ServiceMethod中完成的,每一个接口只初始化一次,并且保存到serviceMethodCache缓存中

  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;
  }

接口初始化的工作包括解析接口参数、解析类似@POST @Body等注解和构建CallAdapter\ResponseConverter等操作,由于代码太多,不做进一步分析了

最后在上一张流程图
这里写图片描述

想要进一步了解retrofit是如何解耦的可以参考Retrofit分析-漂亮的解耦套路

以上!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chengyuan9160

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值