美文网首页
Retrofit源码 - 流程解析

Retrofit源码 - 流程解析

作者: YocnZhao | 来源:发表于2019-02-13 14:59 被阅读0次

    本文基于Retrofit2.5.0分析

        compile 'com.squareup.retrofit2:retrofit:2.5.0'
    

    Retrofit源码用到的主要思想是 动态代理+注解:
    首先我们来看Retrofit的基本用法:
    1、首先有个接口,接口里面有注解标记的方法

    interface IApiService{
        @GET("client_config.json")
        fun getClientConfigModel(): Call<ClientConfigModel>
    }
    

    2、使用create方法获取到上面定义的接口的实例,

    val retrofit = Retrofit.Builder()
            .baseUrl(Constants.URL_BASE_OP_PRE)
            .build()
    val impl:IApiService = retrofit.create(IApiService::class.java)
    

    3、直接使用,调用方法

    RetrofitFactory.impl.getClientConfigModel(url).execute()
    

    上面是Retrofit的基本用法,这里高级API不铺开了。

    下面从入口开始看

    public static final class Builder {
        private final Platform platform; //当前是什么平台Android或者java
        private @Nullable okhttp3.Call.Factory callFactory; //这里看到其实Retrofit跟OKHttp是深度耦合的,无法拆开。
        private @Nullable HttpUrl baseUrl; //baseUrl
    //这里看到converter 和CallAdapter都是可以设置多个的
        private final List<Converter.Factory> converterFactories = new ArrayList<>();
        private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
        private @Nullable Executor callbackExecutor;
        private boolean validateEagerly;
    
        Builder(Platform platform) {
          this.platform = platform;
        }
    
        public Builder() {
          this(Platform.get());
        }
    
        Builder(Retrofit retrofit) {
          //copy target retrofit的属性到自己
        }
    
        public Builder client(OkHttpClient client) {
          return callFactory(checkNotNull(client, "client == null"));
        }
    
        public Builder callFactory(okhttp3.Call.Factory factory) {
          this.callFactory = checkNotNull(factory, "factory == null");
          return this;
        }
    
        public Builder baseUrl(String baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          return baseUrl(HttpUrl.get(baseUrl));
        }
    ··· 
        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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
          callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories = new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    
          // 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());
          converterFactories.addAll(this.converterFactories);
          converterFactories.addAll(platform.defaultConverterFactories());
    
          return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
              unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
        }
      }
    

    Retrofit类的静态内部类Builder,构造器模式构造需要的参数,并构造真正发起网络的OKHttpClient。
    然后调用create方法,也就是动态代理方法

    public <T> T create(final Class<T> service) {
        ...
        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 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);
                }
                return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
              }
            });
      }
    

    对于动态代理技术,可以参考我的一篇文章,最简单的动态代理技术
    有了动态代理的基础后我们发现上面的代码块是一个实现了泛型的动态代理,也就是你给我什么方法我就按照我的逻辑执行什么方法并且返回对应的返回值给你
    我们看最重要的方法其实是

    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
    

    这句话是最终去做事情的一句话,我们跟下去,首先看loadServiceMethod(method)

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

    这里首先做了个缓存,用了

      private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
    

    然后用了synchronized做了个多线程处理,这个HashMap中存的是什么呢?是Method跟ServiceMethod的Key-Value,那ServiceMethod是做什么的呢?

    abstract class ServiceMethod<T> {
      static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
        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.");
        }
    
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
      }
    
      abstract T invoke(Object[] args);
    }
    

    我们根据名字猜测这个是去找我们的写的那些@GET @POST的注解了。
    RequestFactory其实就是来做这个事情的
    RequestFactory的代码就不贴了,太多了,大家可以去看一下RetrofitFactory的代码,就是去规定了那些@GET@POST怎么用的一些规则,包括参数的格式啊,哪些参数应该有body哪些没有body,怎么取内容啊之类的,一堆的if-else。然后存了一些请求的路径端口号什么的。
    我们继续看HttpServiceMethod.parseAnnotations
    这个时候实际上已经把该准备的东西都准备好了,调用parseAnnotations的时候我们直接看HttpServiceMethod代码

    final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
      static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
          Retrofit retrofit, Method method, RequestFactory requestFactory) {
    //构造callAdapter
        CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    //获取response的类型
        Type responseType = callAdapter.responseType();
        ...
    //获取Response转化器
        Converter<ResponseBody, ResponseT> responseConverter =
            createResponseConverter(retrofit, method, responseType);
    
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
      }
    
      private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
          Retrofit retrofit, Method method) {
        Type returnType = method.getGenericReturnType();
        Annotation[] annotations = method.getAnnotations();
        try {
          //noinspection unchecked
          return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
          throw methodError(method, e, "Unable to create call adapter for %s", returnType);
        }
      }
    
      private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
          Retrofit retrofit, Method method, Type responseType) {
        Annotation[] annotations = method.getAnnotations();
        try {
          return retrofit.responseBodyConverter(responseType, annotations);
        } catch (RuntimeException e) { // Wide exception range because factories are user code.
          throw methodError(method, e, "Unable to create converter for %s", responseType);
        }
      }
    
      private final RequestFactory requestFactory;
      private final okhttp3.Call.Factory callFactory;
      private final CallAdapter<ResponseT, ReturnT> callAdapter;
      private final Converter<ResponseBody, ResponseT> responseConverter;
    
      private HttpServiceMethod(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
          CallAdapter<ResponseT, ReturnT> callAdapter,
          Converter<ResponseBody, ResponseT> responseConverter) {
        this.requestFactory = requestFactory;
        this.callFactory = callFactory;
        this.callAdapter = callAdapter;
        this.responseConverter = responseConverter;
      }
    
      @Override ReturnT invoke(Object[] args) {
        return callAdapter.adapt(
            new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
      }
    }
    

    parseAnnotations的时候返回一个HttpServiceMethod对象,里面存储了request跟response需要的工具,然后我们应该还记得最上面动态代理的最后一句

    return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
    

    会调用

    @Override ReturnT invoke(Object[] args) {
        return callAdapter.adapt(
            new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
      }
    

    得到response后对返回结果做处理返回,整个流程就完事儿了,这是大致的流程。后续分析下面继续。


    这里是更深入一些的分析。
    我们从HttpServiceMethod里面看其实一共没几个方法,除了parseAnnotations和invoke,就是createCallAdapter和createResponseConverter了。顾名思义,这两个方法是构造了callAdapter和converter。
    大家常用的CallAdapterConverter大概就是RxJavaCallAdapterFactoryGsonConverterFactory了,
    我理解的calladapter应该是在call之前我们要做的准备工作,像RxJavaCallAdapterFactory把RxJava的东西转化成retrofit需要的数据。
    而Converter则是把请求回来的数据转化成我们想要的对象或者String类型数据。像GsonConverterFactory就是把我们请求回来的String数据转化成我们需要的对象。

    下面我们看源码

    retrofit.responseBodyConverter(responseType, annotations);
    

    像createResponseConverter其实就是调用了responseBodyConverter

    public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
        return nextResponseBodyConverter(null, type, annotations);
      }
      public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
          @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    ...
      int start = converterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          Converter<ResponseBody, ?> converter =
              converterFactories.get(i).responseBodyConverter(type, annotations, this);
          if (converter != null) {
            return (Converter<ResponseBody, T>) converter;
          }
        }
    ...
      }
    
     converterFactories.add(new BuiltInConverters());
          converterFactories.addAll(this.converterFactories);
          converterFactories.addAll(platform.defaultConverterFactories());
    

    最上面build Retrofit的时候有这么一段话,所以这里start就是为了跳过前面添加的。因为Factory.requestBodyConverter 没有实现的时候是返回的null,所以定义的convert的responseBodyConverter如果能匹配上返回类型不返回null,则获取到这个Converter直接返回。所以说如果有两个相同类型的Converter能够匹配同样的ResponseType,那只会取前面的那个,后面的永远到不了。
    所谓的ResponseType就是我们请求的时候的响应类型,比如最上面我们请求的
    fun getClientConfigModel(): Call<ClientConfigModel>
    ResponseType就是ClientConfigModel。所以如果我们使用的时候设置了两个converter

                retrofit = new Retrofit.Builder()
                        .addConverterFactory(new MyConverterFactory())
                        .addConverterFactory(GsonConverterFactory.create())
                        .addCallAdapterFactory(new MyCallAdapterFactory())
                        .baseUrl("https://restapi.amap.com/v3/weather/")
                        .build();
    

    MyConverterFactory和GsonConverterFactory顺序是很关键的,我们可以看GsonConverterFactory的源码,它的responseBodyConverter方法如下:

    @Override
      public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
          Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, adapter);
      }
    

    我们可以看出来它其实cover了所有的类型。那其实如果是下面这个顺序的话

                        .addConverterFactory(GsonConverterFactory.create())
                        .addConverterFactory(new MyConverterFactory())
    

    我们的MyConverterFactory能够实现什么类型都没有用,因为GsonConverterFactory已经全部截胡了,我们MyConverterFactory没有任何的出场机会。但反过来说下面这个顺序的话

                        .addConverterFactory(new MyConverterFactory())
                        .addConverterFactory(GsonConverterFactory.create())
    

    就是先判断MyConverterFactory的类型,如果MyConverterFactory不能接受我们的返回类型在上面

    for (int i = start, count = converterFactories.size(); i < count; i++) {
          Converter<ResponseBody, ?> converter =
              converterFactories.get(i).responseBodyConverter(type, annotations, this);
          if (converter != null) {
            return (Converter<ResponseBody, T>) converter;
          }
        }
    

    就会返回null,然后继续往下for循环,发现GsonConverterFactory可以搞定,就会返回GsonConverterFactory。所以说我们如果需要特殊处理某种类型的话,一定要把它放到前面add进来。否则就是舔到最后一无所有。
    我们如果看过OKHttp的源码,印象很深的应该是责任链模式,也就是interceptor拦截器,我感觉retrofit的这个应该也是有异曲同工之妙的~
    那我们看CallAdapter的处理是类似的,相对来说Converter的自定义的机会多一些,我们就讲Converter了。
    而且我们看invoke方法

    @Override ReturnT invoke(Object[] args) {
        return callAdapter.adapt(
            new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
      }
    

    其实就是调用了callAdapter.adapt方法,而且这个名字起的特别好,adapt就是改编、适应的意思,顾名思义啊,calladapter的作用就是把我们调用的时候的一些东西像RxJava这样的框架的数据改编成我们OKHttp所需要的数据。
    我们看OkHttpCall这个类,继承自Call

    final class OkHttpCall<T> implements Call<T> {
      private final RequestFactory requestFactory;
      private final Object[] args;
      private final okhttp3.Call.Factory callFactory;
      private final Converter<ResponseBody, T> responseConverter;
      private volatile boolean canceled;
      private @Nullable okhttp3.Call rawCall;
      private @Nullable Throwable creationFailure;
      private boolean executed;
    
      OkHttpCall(RequestFactory requestFactory, Object[] args,
          okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {...}
    
      @Override public synchronized Request request() {...}
      @Override public void enqueue(final Callback<T> callback){...}
      @Override public synchronized boolean isExecuted(){...}
      @Override public Response<T> execute() throws IOException {...}
      Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {...}
      public void cancel()  {...}
      @Override public boolean isCanceled(){...}
    
    public interface Call<T> extends Cloneable {
      Response<T> execute() throws IOException;
      void enqueue(Callback<T> callback);
      boolean isExecuted();
      void cancel();
      boolean isCanceled();
      Call<T> clone();
      Request request();
    }
    

    我们发现Retrofit的Call接口几乎就是把OKHttp的Call接口拷贝过来了。所以Retrofit的OKhttpCall就是把OKHttp的请求包了一遍。就是从okhttp3.Request变成了retrofit2.Request。

    下篇写个简单的CallAdapter跟Converter的例子

    总结:

    1. Retrofit2跟OKhttp3深度耦合,无法拆开
    2. Retrofit的调用入口是由一个动态代理实现的,最终调用loadServiceMethod(method).invoke
    3. RequestFactory解析注解找到我们需要调用的方法
    4. 最终调用OKHttp的地方在HttpServiceMethod.invoke
    5. Retrofit接受请求网络前后都的处理流程,开放了callAdapter和converter供我们构造。
    6. converter采用了责任链模式,找到第一个能处理ResponseType的就不再往下处理,否则继续往下找能cover到ResponseType类型的converter
    7. OkHttpCall是Retrofit的Call方法,定义几乎跟OKHttp的接口一样。

    相关文章

      网友评论

          本文标题:Retrofit源码 - 流程解析

          本文链接:https://www.haomeiwen.com/subject/pcdxsqtx.html