Retrofit源码解读

254 阅读8分钟

Retrofit源码解读

从2.6之后,retrofit支持协程使用,而后期android开发语言基本为Kotlin,因此这里面着重分析使用协程下网络请求的执行流程

模块思维导图

Retrofit.png

执行流程图

Retrofit网络请求执行流程.png

源码分析

基于接口创建请求配置

动态创建类

利用java动态代理Proxy,基于接口返回实例
Proxy.newProxyInstance(service.getClassLoader(),
new Class<?>[] {service},Invocationhander)

创建返回实例,其后该类所以的方法调用都通过InvocationHandler调用

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

在invoke方法,其会一次判断

  • 如果是Object的方法,直接调用该方法
  • 如果是已经实现的方法,调用默认实现
  • 最后,如果是接口定义的抽象方法,即Retrofit网络请求方法,进行处理

调用时,invoke会先解析方法,然后调用,解析的入口时loadServiceMethod

解析Method

loadServiceMetod
  • 缓存中获取,有直接返回
  • 缓存没有,创建
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);
      }
    }

创建时调用_parseAnnotations_

  1. ServiceMethod.parseAnnotations(this, method)创建ServiceMethod
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);

其首先会解析方法注解,初始化构建Okhttp.Request的必须参数,然后再去创建体对应的HttpServiceMethod

创建RequestFactory
  • 通过Builder模式创建
 static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

在通过构造模式创建RequestFactory是,其会解析我们添加在方法注解,完成参数的配置

  • 获取方法上对应的注解
Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      //方法上注解
      this.methodAnnotations = method.getAnnotations();
      //获取方法参数类型
      this.parameterTypes = method.getGenericParameterTypes();
       //获取参数上注解
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

  • 构造模式解析方法,返回实例requestFactory
RequestFactory build() {
  //解析方法注解  
  for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }    
  //校验是否配置必须参数,例如请求方法,网络内容格式
  ...
 //解析方法参数注解,并创建对应的解析处理类 
      //解析方法里参数 ,获取方法参数里注解
int parameterCount = parameterAnnotationsArray.length;
      //根据数量和类型创建对应的ParameterHandler
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
  parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }
    //校验方法参数必须的配置是否存在
...
    
 return new RequestFactory(this);   
} 



接下来我们看一下里面内部的两个核心方法parseMethodAnnotation和parseParameter

  • parseMethodAnnotation

...根据对应注解,配置对应的请求方法
//例如Delete,get,post等,不一一列举
if (annotation instanceof GET) {
 parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
}
//解析请求头
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);
        //是否Multipart
      }
//解析是否为二进制Multipart或FormUrlEncoded
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;
      }

接下来重点看一下_parseHttpMethodAndPath_和_parseHeader_,其他只是配置是否,不用深入

 private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
 //检测方法是否已存在,方法注解只能配置一个
   if (this.httpMethod != null) {//抛出异常}
 //设置
   this.httpMethod = httpMethod;
   this.hasBody = hasBody;      
 //获取方法上值,例如@GET("/article/list/")
 
 //校验查询参数配置是否正确,查询通过@Query配置
 int question = value.indexOf('?');
 if (question != -1 && question < value.length() - 1) {
      // Ensure the query string does not have any named parameters.
     //检测查询是否通过filed去配置例如/url?{userName}
     //正确方法method(@Query("sort") String order,@Query("page") Integer page)
      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);
        }
   }
   //配置url参数
 this.relativeUrl = value;
 //解析路径里参数/bottom/navBar/{platform},返回set集合,防止重复添加
 this.relativeUrlParamNames = parsePathParameters(value);      
 }

parseHeader比较简单,即解析Headers字符串,将其添加到_Headers.Builder()_ �中,最终创建Headers

Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
   int colon = header.indexOf(':');
   String headerName = header.substring(0, colon);
   String headerValue = header.substring(colon + 1).trim();
   //处理特殊header,content-type,其值需要额外转换
   if ("Content-Type".equalsIgnoreCase(headerName)) {
       try {
          contentType = MediaType.get(headerValue);
        } catch (IllegalArgumentException e) {
            throw methodError(method, e, "Malformed content type: %s", headerValue);
       }
    } else {
       builder.add(headerName, headerValue);
    }
    return builder.build();

在解析完方法后,就是解析方法参数,其内部会调用parseParameterAnnotation,同时最后会判断是否为协程supsend方法

//解析方法参数里注解
for (Annotation annotation : annotations) {
 ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
}
//判断是否可运行协程
if (allowContinuation) {
          try {
            //判断是否为suspend方法,具体原因是suspend编译后转为java最后一个参数为Continuation  
            if (Utils.getRawType(parameterType) == Continuation.class) {
              isKotlinSuspendFunction = true;
              return null;
            }
          } catch (NoClassDefFoundError ignored) {
          }
        }
  • parseParameterAnnotation
//其就是解析可在方法里配置的各种注解,创建对应的ParameterHandler
//1.解析@Path
if (annotation instanceof Path){
   //规则校验,例如与Query的顺序
   ...
   if (gotQuery) {
throw parameterError(method, p, "A @Path parameter must not come after a @Query.");
   }    
       
   ...    
   Path path = (Path) annotation;
   String name = path.value();
   validatePathName(p, name);

   Converter<?, String> converter = retrofit.stringConverter(type, annotations);
   return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
}
//接下来基本类似,依次解析Query,QueryName
//解析Field
else if (annotation instanceof Field) {
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
//根据不同情况返回不同类型的ParameterHandler.Field
//集合
ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
          Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).iterable();    
}
//数组
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter<?, String> converter =
              retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).array();
//单个
 Converter<?, String> converter = retrofit.stringConverter(type, annotations);
 return new ParameterHandler.Field<>(name, converter, encoded);
//其他基本类似,具体可看ParameterHandler子类,这里不再一叙述

最后即返回requestFactory

创建HttpServiceMethod
  1. 区分为Kotlin的suspend方法还是普通方法

其依据即为我们创建requsetFactory解析参数时的方法里_parseParamete的处理,设置isKotlinSuspendFunction_ �我们重点讲解这个流程

  1. 获取获取参数类型和返回类型

对应协程其返回是通过continuation.resumewith(),所以其返回值在最后一个参数_Continuation_�

//对于协程其最终返回值为<T>,例如Result<List<String>>
public fun resumeWith(result: Result<T>)
//获取函数参数类型
Type[] parameterTypes = method.getGenericParameterTypes();
//获取返回值的类型,细节主要是处理泛型
Type responseType =Utils.getParameterLowerBound(0, (ParameterizedType)parameterTypes[parameterTypes.length - 1]);
//重新包装返回类型,即包装为Call<Type>
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);

//非协程
adapterType = method.getGenericReturnType();
  1. 创建CallAdapter

calladapter最终创建通过calladapterfactory

CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);

createCallAdapter(..){
try {
      //获取Retrofit配置的callAdapter
      //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);
    }

}
//in Retrofit中,调用nextAdapter获取
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  • 判断是否需要跳过的CallAdapter.Factory
  • 遍历添加的calladapterfactories,通过类型获取其是否可创建对应的calladapter
  • 查找到则返回,即其会匹配查找到的第一个
int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
//为查找到,则输出错误信息
....

同时注意,创建Retrofit时,其会添加默认的callAdapter,即如果未查找到对应的,其会使用默认的的,


//在Retrofit.Builder.build方法中
// 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));
  • 获取responseType,检测其是否正确

  1. 创建Response转换类,其过程基本跟clladapter类似,只是创建的类不同
Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

createResponseConverter(...){
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);
    }
}
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, 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) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
  }

//在Retrofit build中,添加自定义和默认的
List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
  1. 设置Okhttp3.Call.Facyory

其左右就是创建真正进行网络请求的Call,获取进行网络请求时会使用它

okhttp3.Call.Factory callFactory = retrofit.callFactory;

6.创建HttpServiceMethod具体对应的类 这个根据是否是协程,即协程返回类型,返回不同的HttpServiceMethod

if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      // suspend method 返回 SuspendForResponse,其为HttpServiceMethod 子类
      //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);
    }

到这里我们就完成了进行网络请求对应的方法类,即其相关的依赖类。

进行网络请求

我们在前面的Retrofit.create里看到其最终会调用创建的ServiceMethod的invoke方法,而在HttpServiceMethod中,其内部会调用adap(call,args),其有具体的子类实现


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

这里我们可以看到,其为了防止子类重写,添加了final,这是因为,其需要传递OkHttpCall,其是最终创建Call的中间处理类,因此禁止子类重写。 OkHttpCall,持有了配置了网络请求参数的requesFactor,args,callFactroy. 下面我们主要分析对协程支持的子类_SuspendForResponse的实现_

SuspendForResponse开始请求

protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);

      //noinspection unchecked Checked by reflection inside RequestFactory.
      Continuation<Response<ResponseT>> continuation =
          (Continuation<Response<ResponseT>>) args[args.length - 1];

      // See SuspendForBody for explanation about this try/catch.
      //扩展Call方法,将任务加入队列
      try {
        return KotlinExtensions.awaitResponse(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }
  1. 适配OkhttpCall
  2. 调用扩展方法等待结果

其中_KotlinExtensions.awaitResponse内部是扩展的Call类的方法,将请求加入队列_

suspend fun <T> Call<T>.awaitResponse(): Response<T> {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }

� 3. 队列创建请求回调 因为传递进来的为OkHttpCall,因此加入队列的方法调用的为其方法,具体语法可查看Kotlin扩展方法实现 在这里会创建真正进行网络请求的Call,即Okhttp3.Call,同时我们通过上面代码也可理解,如果后期网络不是通过Okhttp实现,我们可修改HttpServiceMethod中invoke的call,即可替换为其他网络框架,但这里存在问题就是解析对应的ServiceMethod不支持依赖注入,其方法使用的静态方法,无法扩展。这里只是分析如果要做,要在那里处理 其如此设计,是因为其本身内部引入了Okhttp类,本身就是强依赖,所以相关类都禁止扩展。且Okhtttp底层基于socket,替换的情况很少

创建Okhttp.Call

  1. callFacyory创建call
public void enqueue(final Callback<T> callback) {
   okhttp3.Call call;
     
}

if (call == null && failure == null) {
        try {
          //创建真正进行请求的call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

call的创建通过callFactory,即我们在创建HttpServiceMethod,配置的。这里我们可通过去修改call

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

Okhttp.call,接受的参数为Okhttp.Request

创建Reqeust

解析参数配置
okhttp3.Request create(Object[] args) throws IOException {
...
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

RequestBuilder requestBuilder =
        new RequestBuilder(
            httpMethod,
            baseUrl,
            relativeUrl,
            headers,
            contentType,
            hasBody,
            isFormEncoded,
            isMultipart);
....    
}

这里我们以File为例分析一下

  1. 获取对应的ParameterHandler
  • 对于Kotlin方法,因为最后一个参数不参与解析,修改数量
if (isKotlinSuspendFunction) {
    // The Continuation is the last parameter and the handlers array contains null at that index.
      argumentCount--;
    }
  1. 调用其applay将其设置给requestBuilder
List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      //解析对应的参数
      handlers[p].apply(requestBuilder, args[p]);
    }

我们看一下ParameterHandler.Field

void apply(RequestBuilder builder, @Nullable T value) throws IOException {
      if (value == null) return; // Skip null values.

      String fieldValue = valueConverter.convert(value);
      if (fieldValue == null) return; // Skip null converted values

      builder.addFormField(name, fieldValue, encoded);
    }
  }

其获取注解里的值,然后将其添加到request中

构建请求

通过上面的解析,配置完requestbuilder即可以创建请求

//创建request,并添加tag,方便取消请求,retrofit 默认类都是Invocation
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();

其会给请求添加Tag,因为我们的请求是通过动态代理进行的,因此类都是Invocation,具体的实例根据方法和参数二不同

加入Okhttp请求队列,开始网络请求

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

获取如何分发网络请求处理,都有Okhttp负责,这里只分析Retrofit,到这里即通过Retorfit成功创建了一个网络请求,然后等待结果,进行处理

解析结果

在发起请求后,当成功时,其会调用parseResponse处理开始处理结果

onResponse获取结果

网络请求返回后,调用parseResponse解析结果

 ...
  call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {    
 response = parseResponse(rawResponse);
              
...
}

parseResponse解析结果

创建空body,处理网络请求非成功code
rawResponse =rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

这里使用空body,是后面只是处理code,不解析内容,节省内存和时间

处理非成功结果
  1. 非200范围成功码,返回错误结果
  2. 200范围内,无内容code或只是刷新数据无变化,直接返回

The HTTP 204 No Content success status response code indicates that a request has succeeded, but that the client doesn't need to navigate away from its current page The HTTP 205 Reset Content response status tells the client to reset the document view, so for example to clear the content of a form, reset a canvas state, or to refresh the UI.


int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        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);
    }

convert解析结果

在上面处理完无须解析内容的情况下,调用convert解析结果

try {
      T body = responseConverter.convert(catchingBody);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }

这里我们列举一下,如何使用Gson解析结果,其他例如xml,protobug等可具体使用在分析

gson 转换
 @Override
  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();
    }
  }

在这里我们可以处理我们业务系统自定义code的请求,让业务专注自身。也可提出通用的code,msg,直接返回内容给调用方,避免重复嵌套

Response.success返回结果

 T body = responseConverter.convert(catchingBody);
 return Response.success(body, rawResponse);
转换为Retrofit的Response

其包括原始的Okhttp.Response,和内容body

public static <T> Response<T> success(@Nullable T body, okhttp3.Response rawResponse) {
    Objects.requireNonNull(rawResponse, "rawResponse == null");
    if (!rawResponse.isSuccessful()) {
      throw new IllegalArgumentException("rawResponse must be successful response");
    }
    return new Response<>(rawResponse, body, null);
  }

返回结果到KotlinExtension

在parseResponse返回Response,调用KotlinExtension最初调用传入的callBack返回结果

try {
     callback.onResponse(OkHttpCall.this, response);
    } catch (Throwable t) {
       throwIfFatal(t);
      t.printStackTrace(); // TODO this is not great
   }

该callBack为匿名类,

continuation返回结果

object : Callback<T> {
      override fun onResponse(call: Call<T>, response: Response<T>) {
        continuation.resume(response)
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })

到此,我们就梳理完了使用Retrofit从创建类,到开始请求,到最后返回结果的整个流程。

UML类图关系

Retrofit类关系.png

思考