Retrofit源码解析

166 阅读17分钟

总结源码流程

  1. 通过Retrofit.create(Class)方法创建出Server interface的实例

    • Retrofit.create(Class)方法内部,使用Proxy.newProxyInstance()方法创建出Server实例。这个方法会为参数中的多个Interface(具体到Retrofit来说,是固定传入一个Interface)创建对象。这个对象实现了所有interface的每一个方法。使用动态代理实现了对象创建,即InvocationHandler.invke()方法。

    • InvocationHandler.invke()方法实现如下:

      1. 创建ServerMethod

        ServerMethod<Object, Object> ServerMethod =
         (ServerMethod<Object, Object>) loadServerMethod(method);
        

        读取interface中方法的所有信息(返回类型,参数,参数注解,反射注解),并初步分析。

      2. 创建OkHttpCall

        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(ServerMethod, args);
        

        okHttpCall是retrofit2.call的子类,将ServerMethod封装至一个retrofit2.call对象。在enqueue()方法调用的时候用ServerMethod中包含的信息创建出OkHttp3.call对象。并调用发起网络请求。并对结果做预处理

      3. adapt()

        return ServerMethod.adapt(okHttpCall);
        

        会使用ServerMethod中的CallAdapter对象吧OkhttpCall对象进行转换,生成一个新的Retrofit2.Call对象,并且后台线程发起请求,主线程回调处理结果,完成切换线程的工作。还可以生成Obervable等对象。

A type-safe HTTP client for Android and Java.

Retrofit源码结构不算很复杂,此次解析的Retrofit版本为2.9.0。

2.9.0版本和老版的Retrofit的概念模型差距不大,但是对整体结构变化较大。

本文预计游览时间16分钟,建议使用Night主题查看


基本使用

解析实例先引用最简单的Call实现为例子。

  1. Retrofit创建
 val retrofit = Retrofit.Builder()
                .baseUrl("https://wanandroid.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
  1. interface声明
 interface WanAndroidApi {
    @GET("article/listproject/{pageindex}/json")
    fun getProjectListWithCall(@Path("pageindex") pageindex: Int): Call<BaseModel<ProjectListBean>>
}
  1. API创建
var wanAndroidApi = retrofit.create(WanAndroidApi::class.java)
  1. 请求
wanAndroidApi.getProjectListWithCall(0)
            .enqueue(object : Callback<BaseModel<ProjectListBean>> {
                override fun onFailure(call: Call<BaseModel<ProjectListBean>>, t: Throwable) {
                    Timber.i(t)
                }

                override fun onResponse(
                    call: Call<BaseModel<ProjectListBean>>,
                    response: Response<BaseModel<ProjectListBean>>
                ) {
                    Timber.i(response.toString())
                }
            })

首先按照程序入口,我们分析下retrofit的创建过程

Retrofit.Builder()

Platform

Platform.get()
  1. 首先会在Builder的构造里调用Platform.get()的方法,追踪代码,最后执行到findPlatform()方法。findPlatform()方法会根据虚拟机平台去具体平台,代码如下。
public Builder() {
	this(Platform.get());
}

static Platform get() {
	return PLATFORM;
}

private static final Platform PLATFORM = findPlatform();

private static Platform findPlatform() {
	return "Dalvik".equals(System.getProperty("java.vm.name"))
		? new Android() //
		: new Platform(true);
}

  1. Platform构造的hasJava8Types参数用于区分是否支持java8平台,如果是java8平台,Retrofit通过MethodHandle去检测是否有私有接口,并且通过反射开启访问限制。
Platform(boolean hasJava8Types) {
	this.hasJava8Types = hasJava8Types;
	Constructor<Lookup> lookupConstructor = null;
	if (hasJava8Types) {
	  try {
		lookupConstructor = Lookup.class.getDeclaredConstructor(Class.class, int.class);
		lookupConstructor.setAccessible(true);
	  } catch (NoClassDefFoundError ignored) {
	  } catch (NoSuchMethodException ignored) {
	  }
	}
	this.lookupConstructor = lookupConstructor;
}

另外还做了异常处理

1.虑到了Android API 24 或者 25下,Lookup.class是不存在的,捕捉了NoClassDefFoundError 2.在JDK 14以下是没有getDeclaredConstructor方法的,捕获了NoSuchMethodException


  1. Android是继承Platform的实现,构造通过SDK版本判断,如果大于23会开启JAVA8支持。并且重写了defaultCallbackExecutor()方法,提供了MainThreadExecutor。其内部会获取MainLooper构建handler,execute方法直接handler.post(runnable),实现在主线程上的操作。
static final class Android extends Platform {
    Android() {
      super(Build.VERSION.SDK_INT >= 24);
    }

    @Override
    public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Nullable
    @Override
    Object invokeDefaultMethod(
        Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
      if (Build.VERSION.SDK_INT < 26) {
        throw new UnsupportedOperationException(
            "Calling default methods on API 24 and 25 is not supported");
      }
      return super.invokeDefaultMethod(method, declaringClass, object, args);
    }

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

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

  1. 除了介绍Platform的获取,还有一些关键方法。
defaultCallAdapterFactories()

​ 这个方法是提供了默认的CallAdapter,所以在初始化Retrofit时不调用addCallAdapterFactory()方法也有默认实现。

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
	DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
	return hasJava8Types
		? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
		: singletonList(executorFactory);
}
  • 通过hasJava8Types区分java平台,如果不是JAVA8平台就会只添加一个DefaultCallAdapterFactory。如果是的话还会多添加一个CompletableFutureCallAdapterFactory。为了减少代码理解复杂程度,我们先只看DefaultCallAdapterFactory的实现,CompletableFutureCallAdapterFactory下文会详细介绍。

CompletableFutureCallAdapterFactory其实是对CompletableFuture进行了适配。CompletableFuture提供了异步函数式编程,CompletableFuture提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法


defaultConverterFactories()

​ 这个方法依然是根据hasJava8Types区分返回OptionalConverterFactory还是emptyList。

List<? extends Converter.Factory> defaultConverterFactories() {
	return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList();
}

Builder()

  1. 现在回到最初的.Builder()方法,我们看一下完整实现。除了Platform的赋值,还实现了以下属性。
变量说明
baseUrl默认地址
callFactory:okhttp3.Call.Factoryokhttp默认实现的工厂
callbackExecutor默认的请求回调池
validateEagerly是否进行激进化验证
Builder(Retrofit retrofit) {
      platform = Platform.get();
      callFactory = retrofit.callFactory;
      baseUrl = retrofit.baseUrl;
    
      for (int i = 1,size = retrofit.converterFactories.size() - platform.defaultConverterFactoriesSize();i < size;i++) {
        converterFactories.add(retrofit.converterFactories.get(i));
      }
      for (int i = 0,size =retrofit.callAdapterFactories.size() - platform.defaultCallAdapterFactoriesSize();i < size;i++) {
        callAdapterFactories.add(retrofit.callAdapterFactories.get(i));
      }
      callbackExecutor = retrofit.callbackExecutor;
      validateEagerly = retrofit.validateEagerly;
}

其实这个方法只能通过.build()之后的newBuilder()方法才能调到,Retrofit很巧妙的让开发者在build之后还能再次通过newBuilder()拿到Builder对象,然后通过addCallAdapterFactory一类的方法添加到已有的对象属性里。


build()

  1. 看完Builder()方法,我们来看下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();
      }

      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      List<Converter.Factory> converterFactories =new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());


      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

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

Retrofit(
      okhttp3.Call.Factory callFactory,
      HttpUrl baseUrl,
      List<Converter.Factory> converterFactories,
      List<CallAdapter.Factory> callAdapterFactories,
      @Nullable Executor callbackExecutor,
      boolean validateEagerly) {
    this.callFactory = callFactory;
    this.baseUrl = baseUrl;
    this.converterFactories = converterFactories; 
    this.callAdapterFactories = callAdapterFactories; 
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
  }

实现了如下功能:

  1. 检查BaseUrl的是否为空,如果为空抛出Base URL required.
  2. 检查callFactory是否为空,如果为空指定OkHttpClient();
  3. 检查callbackExecutor是否为空,如果为空指定为platform的默认回调线程池。也就是说如果平台为Android,默认提供MainThreadExecutor()。
  4. 把platform默认提供的默认的Call对象转换器添加到callAdapterFactories。按照刚才的思路,也就是添加了DefaultCallAdapterFactory的实现。
  5. 根据之前传入的Converter.Factory的size+platform提供的默认转换器工厂的size+1,创建出converterFactories,为后期的转换提供默认实现。
  6. 最后把上面说明的属性全部赋值。

最后我们整合下Retrofit.Builder()........build()整体思路,概念模型思路如下(除去细节)

  1. 首先区分出是Android平台还是java平台,用于初始化默认的defaultCallAdapterFactories和defaultConverterFactories。
  2. 根据初始化的各个属性,在调用build()时,把各个属性进行赋值

是不是其实很简单。


create()

基于我们分析的基本概念模型,接下来我们从.create()方法入手,分析Retrofit的核心代码。

 public <T> T create(final Class<T> service) {
    validateServiceInterface(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 @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.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

validateServiceInterface()

  1. 首先第一步调用了validateServiceInterface(service)方法,也就是上文分析得出的激进化验证,代码实现如下
private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    
    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message = new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
        if (candidate != service) { message.append(" which is an interface of ").append(service.getName()); }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          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;
  }

代码其实很简单,实现了如下功能:

  1. 验证传入的service是否是interfaces,不是则抛出API declarations must be interfaces.

  2. 基于ArrayDeque双向列表实现service的检查管理。检查内容如下:

    2.1. 先把service填入到列表check,然后进行while循环检查

    2.2. 然后把刚才加入的service删除掉,对次service进行检查

    2.3. 检查类型参数的准确性,检查实例是否同步

    2.4. 如果检查未通过,则直接抛出异常,如果检查通过,重新添加至列表check

  3. 如果validateEagerly为true,则进入激进化验证。首先会过滤掉service的默认方法和静态方法。

  4. 然后执行loadServiceMethod()方法

  5. 把过滤之后的方法,在同步代码块内部调用ServiceMethod.parseAnnotations(this, method);方法,方法会在内部继续判断过滤,如果通过,则添加到serviceMethodCache之中。serviceMethodCache是ConcurrentHashMap,也就是线程安全的HashMap。能看出Retrofit 的代码十分严谨。


parseAnnotations()

  1. 分析得出我们需要看ServiceMethod的parseAnnotations方法,此方法很关键,其实调用了parseAnnotations()方法和build()方法,实现如下:
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);
 }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      return new RequestFactory(this);
    }

首先看Builder构造,代码如下:

Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

很简单,就是Retrofit实例的赋值,方法的赋值,方法注解的赋值,参数类型的赋值,参数注解列表的赋值。


接下里分析build()的内部实现,内部关键方法为parseMethodAnnotation()和parseParameterAnnotation()。除两方法之外还有一些其他预处理。

parseMethodAnnotation()

  1. 调用parseMethodAnnotation()方法把接口获取的方法注解(methodAnnotations)进行准确性检查。并根据请求方法预处理。处理内容如下:

    1.1 会根据httpMethod是否为空判断,限制只有一个Http方法被允许,不能允许多个Http方法.

    1.2 通过正则判断是否包含替换符,如果包含则抛出异常

    1.3 根据请求方法预处理是否hasBody

    1.4 如果包含Headers注解,判断Headers内容是否为空,如果为空抛出@Headers annotation is empty.

    1.5 如果包含Multipart注解,判断isFormEncoded是否为True,如果为True抛出Only one encoding annotation is allowed.

    1.6 如果包含FormUrlEncoded注解,判断isMultipart是否为True,如果为True抛出Only one encoding annotation is allowed.

    1.7 直到如上检查都通过则对relativeUrl(相对路径url),relativeUrlParamNames(相对路径参数)赋值.

    ps.也就是只有一种编码注解

代码如下:

 private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
///////////////////////////////////////////////////////////////////////////
 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError(
            method,
            "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod,
            httpMethod);
      }
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // Get the relative URL path and existing query string, if present.
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError(
              method,
              "URL query string \"%s\" must not have replace block. "
                  + "For dynamic query parameters use @Query.",
              queryParams);
        }
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

parseParameterAnnotation()

  1. URL注解和PATH注解单独预处理,必须在其他参数之前

  2. 实在太长了不想解析了,没什么难度,有兴趣的自己去看把

    ps.此方法代码近500,不与贴出。


其他预处理,代码如下:

if (httpMethod == null) {
    throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
   if (isMultipart) {
     throw methodError( method,"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
   }
   if (isFormEncoded) {
     throw methodError(method,"FormUrlEncoded can only be specified on HTTP methods with request body (e.g., @POST).");
   }
}
if (relativeUrl == null && !gotUrl) {throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {throw methodError(method, "Non-body HTTP method cannot contain @Body.");}
if (isFormEncoded && !gotField) {throw methodError(method, "Form-encoded method must contain at least one @Field.");}
if (isMultipart && !gotPart) {throw methodError(method, "Multipart method must contain at least one @Part.");}
  1. 对方法检查是否为空.
  2. 如果hasBody为false,但是添加了Multipart支持,抛出异常Multipart can only be specified on HTTP methods with request body (e.g., @POST)。也就是限制Multipart下的请求方式。
  3. 其实还是限制,get请求下不能支持FormUrlEncoded
  4. 判断参数和真实URL是否为空
  5. 不含有body的请求不能含有@Body注解
  6. Form-encoded需要有至少一个@Field
  7. Multipart方法至少含有一个@Part

HttpServiceMethod.parseAnnotations()

  1. 直到如上代码执行完毕,会返回RequestFactory对象。然后HttpServiceMethod会调用**parseAnnotations()**方法,传入requestFactory对象。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }

    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    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);
    }
  }

HttpServiceMethod这个类其实就是把一个Retrofit接口适配成一个真实的HttpCall,然而parseAnnotations()方法就是关键,分析如下:

  1. 首先会根据requestFactory.isKotlinSuspendFunction判断是否是一个Kotlin协程方法,如果是的话做出如下处理:

    1.1. 如果返回的变量类型是Response,并且是一个参数化类型,记录返回类型的上界并且标记为需要持续响应。

    1.2. 然后根据Utils.ParameterizedTypeImpl()方法返回参数类型的真实实例。

    1.3. 判断是否有SkipCallbackExecutor注解,去确认是否跳过。

    1.4. 如果不是Kotlin协程方法的话,直接通过method.getGenericReturnType()返回参数真实类型。

  2. 通过createCallAdapter()方法返回真实的CallAdapter,其实调用了retrofit.callAdapter()->nextCallAdapter()方法

    2.1. 通过一开始我们分析Retrofit.callAdapterFactories里放的是各种类型的CallAdapter实例,默认已经有了DefaultCallAdapterFactory和CompletableFutureCallAdapterFactory两个CallAdapter。但是我们先分析DefaultCallAdapterFactory。

    2.2. 其实这个时候就会通过returnType和annotations从callAdapterFactories取得对应的CallAdapter实例。

    2.3. 如果没有找到对应类型的CallAdapter,则会抛出异常.

  3. 判断响应返回类型是不是okhttp3.Respons,如果是就抛出异常。

  4. 判断响应返回类型的Response必须指定参数化,不能是一个非参数类型。

  5. 判断如果请求类型为HEAD,则不能包含返回类型

  6. 通过createResponseConverter()方法返回真实的ResponseConverter,其实调用了retrofit.responseBodyConverter()->nextResponseBodyConverter()方法

    6.1. 同理也是通过returnType和annotations从converterFactories取得对应的ResponseConverter

    6.2. 如果没有找到对应类型的ResponseConverter,则会抛出异常

  7. 如果不是Kotlin协程方法,则会把刚才的requestFactory,callFactory,responseConverter,callAdapter组合成一个CallAdapted

  8. 如是Kotlin协程方法

    8.1. 如果是持续响应方法,则返回SuspendForResponse

    8.2. 如果不是持续响应方法,则返回SuspendForBody


DefaultCallAdapterFactory

  1. 这时我们分析以下上文还未分析的DefaultCallAdapterFactory

    我们先看DefaultCallAdapterFactory的get方法,其实大部分代码都是做安全性和准确性检查。关键代码只有最后return的CallAdapter对象,和内部重写的adapt方法。adapt方法会根据传入的executor检查返回ExecutorCallbackCall对象。

@Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

      @Override
      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

get方法的检查内容如下:

1.通过getRawType()方法判断原始类型是否为Call 2.判断返回类型是否为Call的包装类 3.检查是否添加了SkipCallbackExecutor注解,如果添加了则跳过处理 4.通过 Utils.getParameterUpperBound()通过通配符表达式获取到真实的返回类型的上界,但是会在内部做一些安全操作。下方是代码实现

static Type getParameterUpperBound(int index, ParameterizedType type) {
Type[] types = type.getActualTypeArguments();
if (index < 0 || index >= types.length) {
throw new IllegalArgumentException(
"Index " + index + " not in range [0," + types.length + ") for " + type);
}
Type paramType = types[index];
if (paramType instanceof WildcardType) {
return ((WildcardType) paramType).getUpperBounds()[0];
}
return paramType;
}

至此为止,我们知道adapt方法返回了ExecutorCallbackCall,至于ExecutorCallbackCall具体做了什么,我们先保留。但是了解到DefaultCallAdapterFactory其实就是真实Call对象的转换器。


Proxy.newProxyInstance()

  1. Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)

    1. $Proxy0 实现了我们给的接口Sourceable 并且继承了Proxy,构造类要传入我们使用newProxyInstance时用的InvocationHandler变量,并且在static静态初始化中把Sourceable接口的各个方法Method初始化完成(包括equals,toString等方法),并且真正执行方法的时候实际上是执行InvocationHandler对象的invoke()方法(super.h就是保存在父类Proxy中的InvocationHandler对象),各个方法的区别就是Method对象不同而已,所以真正方法的执行是在InvocationHandler的invoke()方法中完成的。 这也说明了代理逻辑 和 动态代理本身是代码分离的,开发者只需要关注好自己的代理逻辑就行,动态代理本身就交给jdk本身去处理。代码如下:

      @CallerSensitive
      public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
             throws IllegalArgumentException{
             Objects.requireNonNull(h);
             final Class<?>[] intfs = interfaces.clone();
             final SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
                 checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
             }
             Class<?> cl = getProxyClass0(loader, intfs);
             try {
                 if (sm != null) {
                     checkNewProxyPermission(Reflection.getCallerClass(), cl);
                 }
                 final Constructor<?> cons = cl.getConstructor(constructorParams);
                 final InvocationHandler ih = h;
                 if (!Modifier.isPublic(cl.getModifiers())) {
                     AccessController.doPrivileged(new PrivilegedAction<Void>() {
                         public Void run() {
                             cons.setAccessible(true);
                             return null;
                         }
                     });
                     cons.setAccessible(true);
                 }
                 return cons.newInstance(new Object[]{h});
             } catch (IllegalAccessException|InstantiationException e) {
                 throw new InternalError(e.toString(), e);
             } catch (InvocationTargetException e) {
                 Throwable t = e.getCause();
                 if (t instanceof RuntimeException) {
                     throw (RuntimeException) t;
                 } else {
                     throw new InternalError(t.toString(), t);
                 }
             } catch (NoSuchMethodException e) {
                 throw new InternalError(e.toString(), e);
             }
         }
      
      1. 检查 h 不为空,否则抛异常
      2. 对传入的接口做安全检查
      3. 实现动态代理的核心方法,动态代理的思路便是生成一个新类,刚刚getProxyClass0便成为了生成新类
      4. 根据生成的class通过反射获取构造函数对象并生成代理类实例

    2. 经过对newProxyInstance方法分析,得出其实就是看invoke的实现,代码跟踪之后找到如下实现

      @Override
        final @Nullable ReturnT invoke(Object[] args) {
          Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
          return adapt(call, args);
        }
      
      OkHttpCall

      我们分两步,先看生成的OkHttpCall

      OkHttpCall(
            RequestFactory requestFactory,
            Object[] args,
            okhttp3.Call.Factory callFactory,
            Converter<ResponseBody, T> responseConverter) {
          this.requestFactory = requestFactory;
          this.args = args;
          this.callFactory = callFactory;
          this.responseConverter = responseConverter;
        }
      

      其实非常简单,就是把之前获取的RequestFactory,callFactory,responseConverter都提供给OkHttpCall,这个时候我们就应该能得出了,这个就是真实OkhttpCall。OkHttpCall还有一些方法我们开始分析


      1. getRawCall()
        private okhttp3.Call getRawCall() throws IOException {
            okhttp3.Call call = rawCall;
            if (call != null) return call;
            if (creationFailure != null) {
              if (creationFailure instanceof IOException) {
                throw (IOException) creationFailure;
              } else if (creationFailure instanceof RuntimeException) {
                throw (RuntimeException) creationFailure;
              } else {
                throw (Error) creationFailure;
              }
            }
            try {
              return rawCall = createRawCall();
            } catch (RuntimeException | Error | IOException e) {
              throwIfFatal(e); // Do not assign a fatal error to creationFailure.
              creationFailure = e;
              throw e;
            }
          }
        
        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;
          }
        

        代码实现就如方法名,获取未处理的Call,但是内部还有一些逻辑,例如RequestFactory.create()方法内部的RequestBuilder创建获取过程就不介绍了,代码很简单,大家可以随后看。


      2. enqueue()

        public void enqueue(final Callback<T> callback) {
            Objects.requireNonNull(callback, "callback == null");
            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 {
                  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
                    }
                  }
                });
          }
        

        这个方法就很熟悉了,其实就是外部开发者调用的enqueue方法具体实现,解析如下:

        1. 在同步代码块中通过executed判断是否执行过。

        2. 对rawCall和creationFailure做预处理,rawCall如果为空则通过createRawCall()方法获取(就是我们上文分析的创建过程),如果获取失败则把失败信息赋值给creationFailure

        3. 如果队列被取消,则通过canceled判断做Call的cancel

        4. 执行call.enqueue()方法,内部有两个回调

          4.1. onResponse() 进入回调则执行parseResponse()方法,方法下文分析,然后调用callback.onResponse(OkHttpCall.this, response)提供给开发者实现

          4.1. onFailure() 进入回调则执行callFailure(e),然后调用callback.onFailure(OkHttpCall.this, e)提供给开发之是实现


      3. parseResponse()

         Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
            ResponseBody rawBody = rawResponse.body();
            rawResponse =rawResponse
                    .newBuilder()
                    .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
                    .build();
        
            int code = rawResponse.code();
            if (code < 200 || code >= 300) {
              try {
                ResponseBody bufferedBody = Utils.buffer(rawBody);
                return Response.error(bufferedBody, rawResponse);
              } finally {
                rawBody.close();
              }
            }
        
            if (code == 204 || code == 205) {
              rawBody.close();
              return Response.success(null, rawResponse);
            }
        
            ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
            try {
              T body = responseConverter.convert(catchingBody);
              return Response.success(body, rawResponse);
            } catch (RuntimeException e) {
              catchingBody.throwIfCaught();
              throw e;
            }
          }
        
        1. 通过rawResponse的二次build方法把Okhttp.Response移除,因为rawBody是有状态的对象,防止多次读取,所以先移除

        2. 如果返回状态码小于200或者大于300会做结果整体缓冲,以避免将来再次请求的I/O负荷

        3. 如果状态码为204或者205直接返回success,因为204状态码是预检请求,205和204一样,但是要求开发者响应试图

        4. ExceptionCatchingResponseBody在创建时其实用到了Okio.buffer()的,我们之后专门分一期讲解OKio

        5. 然后用之前我们分析的responseConverter的convert()方法转换了开发者需要的返回实体,我们简单看一下GsonResponseBodyConverter的convert()实现

          public T convert(ResponseBody value) throws IOException {
            JsonReader jsonReader = gson.newJsonReader(value.charStream());
            try {
              T result = adapter.read(jsonReader);
              if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
                throw new JsonIOException("JSON document was not fully consumed.");
              }
              return result;
            } finally {
              value.close();
            }
          }
          

          其实很简单,通过字符流生成jsonReader然后再通过TypeAdapter做类型转换,最后返回开发者需要的类型


      4. execute()

        public Response<T> execute() throws IOException {
          okhttp3.Call call;
          synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;
            call = getRawCall();
          }
          if (canceled) {
            call.cancel();
          }
          return parseResponse(call.execute());
        }
        
        1. 就是做了同步代码块的是否执行过的处理

      在invoke方法内部分析完OkHttpCall的诞生和内部的方法,我们来看最关键的方法,就是adapt(),先回顾一下代码

      final @Nullable ReturnT invoke(Object[] args) {
        Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
        return adapt(call, args);
      }
      

      这里我们还是拿DefaultCallAdapterFactory为分析对象,上文我们分析了get方法,但是还遗留了ExecutorCallbackCall这个内部类和adapt方法

      public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, 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) {
            Objects.requireNonNull(callback, "callback == null");
      
            delegate.enqueue(
                new Callback<T>() {
                  @Override
                  public void onResponse(Call<T> call, final Response<T> response) {
                    callbackExecutor.execute(
                        () -> {
                          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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
                  }
                });
          }
      
          @Override
          public boolean isExecuted() {
            return delegate.isExecuted();
          }
      
          @Override
          public Response<T> execute() throws IOException {
            return delegate.execute();
          }
      
          @Override
          public void cancel() {
            delegate.cancel();
          }
      
          @Override
          public boolean isCanceled() {
            return delegate.isCanceled();
          }
      
          @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
          @Override
          public Call<T> clone() {
            return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
          }
      
          @Override
          public Request request() {
            return delegate.request();
          }
      
          @Override
          public Timeout timeout() {
            return delegate.timeout();
          }
        }
      
      1. 根据ExecutorCallbackCall的构造得出需要executor和Call两个实例

        1.1. executor其实就是上文分析的Platform里的Android的MainThreadExecutor

        1.2. Call其实就是传入的代理对象,然而Call本质就是Cloneable

      2. 然后我们分析enqueue,其实这就是Call也就是Cloneable执行的地方,然后在MainThreadExecutor.execute方法里通过Cloneable的状态去调用callback的对应方法

      3. 其他还有一些辅助方法,例如isExecuted,execute,cancel,isCanceled,clone,request,timeout,其实就是状态提供实现,值得一提的是clone是深度克隆


最终概念模型

经过以上分析我们得出梳理下retrofit.create()的概念模型(除去细节)

  1. 在validateServiceInterface()方法里基于ArrayDeque双向列表实现service的检查管理

  2. 在loadServiceMethod()方法里通过ServiceMethod.parseAnnotations()方法返回ServiceMethod添加到serviceMethodCache

    2.1. 调用了RequestFactoryparseAnnotations()方法,最终执行了内部的BuilderBuid方法

    2.2. 在Buid方法内部通过parseMethodAnnotation()对方法注解做预处理,通过parseParameterAnnotation()方法对参数注解做预处理,还有一些其他处理,最终返回requestFactory

    2.3. 把返回的requestFactory传给HttpServiceMethod.parseAnnotations()返回HttpServiceMethod

    2.4. HttpServiceMethod.parseAnnotations()方法其实内部判断了是否支持Kotlin协程和一些预处理,再根据返回类型和转换类型把Platform默认提供或者开发者提供的callFactoryresponseConverter注入到HttpServiceMethod实例中

  3. 通过Proxy.newProxyInstance生成动态代理模型,然后在具体的invoke方法之中处理

    3.1. invoke的实现其实就是先通过之前的requestFactory,callFactory,responseConverter生成OkHttpCall对象。

    3.2. 然后开发者在外部调用.enqueue()方法其实根本就是调用OkHttpCallenqueue()方法,去执行真实的网络请求

    3.3. 在onResponse()方法里通过parseResponse转换为需要的返回类型。


类说明

这个时候整体思路已经完全理清,我们总结下Retrofit涉及到的类与说明

类名关键方法说明
Retrofit内部Builder
Builder的addConverterFactory()
Builder的addCallAdapterFactory()
Builder的build()
create()
validateServiceInterface()
loadServiceMethod()
nextCallAdapter()
nextResponseBodyConverter()
Retrofit核心类
PlatformfindPlatform()
defaultCallbackExecutor()
defaultCallAdapterFactories()
defaultConverterFactories()
invokeDefaultMethod()
平台类,提供java和Android平台,提供了默认的ConverterFactory和CallAdapterFactory和defaultCallbackExecutor
ServiceMethodparseAnnotations()
invoke()
是一个负责转化(适配)的类,负责把一个接口的抽象方法的执行过程的结果转化(适配)成一个网络请求(HTTP call)
RequestFactoryparseMethodAnnotation()
parseParameterAnnotation()
对接口的方法注解和参数注解做相关预处理
HttpServiceMethodparseAnnotations()
createCallAdapter()
createResponseConverter()
根据接口方法返回类型做CallAdapter和ResponseConverter的预处理
OkHttpCallgetRawCall()
enqueue()
parseResponse()
真实Okhttp的实例以及call调用处理和转换处理