Retrofit源碼分析

前言

上篇文章簡單分析了OkHttp的源碼,本篇文章來分析下Retrofit的源碼實現,從Retrofit的簡單使用方式出發java

1、簡單使用

首先須要定義一個網絡請求的API接口,內部配合註解聲明瞭請求方法、請求地址等信息,而後須要建立Retrofit實例,接着調用其create方法建立一個API接口實現類的一個實例,而後就能夠經過調用該實例的指定方法拿到Call實例,接下來就和OkHttp的使用方式沒有什麼不一樣了json

interface DoubanAPI {
    @GET("v2/movie/in_theaters")
    fun inTheaters(@Query("start") start: Int) : Call<ResponseBody>
}
fun main() {
    val retrofit = Retrofit.Builder()
            .baseUrl("https://api.douban.com/")
            .validateEagerly(true)
            .build()
    val api = retrofit.create(DoubanAPI::class.java)
    val call = api.inTheaters(10)
    val response = call.execute()
    if (response.isSuccessful) {
        println("請求成功: ${response.body()!!.string()}")
    } else {
        println("請求失敗: ${response.message()}")
    }
}
複製代碼

接下來按照Retrofit實例的建立、retrofit.create方法的調用、api.inTheater方法的調用、call.execute方法的調用來分析Retrofit的源碼。api

2、Retrofit實例的構建

這裏使用了建造者模式構建Retrofit實例所以首先看看Builder的構造方法數組

public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    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() {
        // 經過反射來判斷是Android仍是Java8
        this(Platform.get());
    }
}
複製代碼

接着又調用了baseUrl方法用來設置當前Retrofit的baseUrl緩存

public Builder baseUrl(String baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
    checkNotNull(baseUrl, "baseUrl == null");
    List<String> pathSegments = baseUrl.pathSegments();
    // 要求baseUrl必需要以/結尾
    if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
    }
    this.baseUrl = baseUrl;
    return this;
}
複製代碼

而後咱們就直接執行build方法構造Retrofit實例網絡

public Retrofit build() {
    // baseUrl是必須的,就算沒用也得設置一個
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }
    okhttp3.Call.Factory callFactory = this.callFactory;
    // 若是沒有設置callFactory就設置一個OkHttpClient實例賦值給callFactory
    if (callFactory == null) {
        callFactory = new OkHttpClient();
    }
    Executor callbackExecutor = this.callbackExecutor;
    // 若是沒有設置callbackExecutor就設置,若是是Android會設置一個MainThreadExecutor,用於將回調切換到主線程執行
    if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
    }
    // 將外界添加的CallAdapter.Factory與系統自帶的CallAdapter.Factory合併,好比RXjava提供的RxJava2CallAdapterFactory,注意用戶的優先
    List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
    // 在Android中若是API>=24會擁有CompletableFutureCallAdapterFactory、ExecutorCallAdapterFactory兩個實例
    callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    // 添加ConvertFactory,API24會默認擁有BuiltInConverters、OptionalConverterFactory
    List<Converter.Factory> converterFactories = new ArrayList<>(
            1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    converterFactories.add(new BuiltInConverters());
    converterFactories.addAll(this.converterFactories);
    converterFactories.addAll(platform.defaultConverterFactories());
    // 其中validateEagerly表示是否急切的驗證方法的合法性
    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; // Copy+unmodifiable at call site.
    this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
    this.callbackExecutor = callbackExecutor;
    this.validateEagerly = validateEagerly;
}
複製代碼

到此爲止Retrofit實例已經建立完畢,接下來看看其create方法app

3、retrofit.create方法的調用

create方法內部作的事情主要有註解解析,動態代理,先來看看註解解析過程ide

註解解析

public <T> T create(final Class<T> service) {
    // 判斷下傳入的Class實例是不是接口,而且判斷其是否繼承了其它接口
    Utils.validateServiceInterface(service);
    // 若是該屬性爲true,在create方法執行的時候就會檢查接口方法的合法性,否則要等到調用指定方法的時候纔會檢查
    if (validateEagerly) {  
        eagerlyValidateMethods(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 (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);
          }
        });
}
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
        // 若是不是默認方法就執行加載
        if (!platform.isDefaultMethod(method)) {
            loadServiceMethod(method);
        }
    }
}
ServiceMethod<?> loadServiceMethod(Method method) {
    // 從緩存中取,取到就直接返回(eagerlyValidateMethods是取不到的)
    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;
}
複製代碼

接着調用了parseAnnotations用於解析接口中每個方法上的註解post

// ServiceMethod.java
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);
}
// RequestFactory.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
}
// 讀取了方法的註解,方法參數類型,方法參數註解
Builder(Retrofit retrofit, Method method) {
    this.retrofit = retrofit;
    this.method = method;
    this.methodAnnotations = method.getAnnotations();
    this.parameterTypes = method.getGenericParameterTypes();
    this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
    // 首先解析了每一個方法上面的註解
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }
    // 必需要有請求方法否則拋出錯誤
    if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
    }
    // 若是這個請求不須要有請求體(根據請求方法判斷),可是設置了Multipart或者isFormEncoded就拋出錯誤
    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).");
            }
        }
    }
    // 獲取方法參數數量
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0; p < parameterCount; p++) {
        parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
    }
    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.");
    }
    return new RequestFactory(this);
}
複製代碼

build方法內部又分別解析了每一個方法上面的註解和每一個方法參數上面的註解ui

1. 解析方法上的註解

來看看parseMethodAnnotation這個方法內部幹了些什麼

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;
    }
}
複製代碼

該方法解析了全部接口方法上面的註釋,其中Mutipart、FormUrlEncoded這裏處理比較簡單就是二者不能共存,DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS處理方式都同樣都是直接調用了parseHttpMethodAndPath

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;
    }
    // 若是url中包含?號那麼就至關於有請求參數
    int question = value.indexOf('?');
    if (question != -1 && question < value.length() - 1) {
        // 將查詢參數字符串切割出來
        String queryParams = value.substring(question + 1);
        // 查詢參數裏面不容許使用{參數}的方式,取代方法是使用@Query註解
        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;
    // 將url中的{參數}找出來
    this.relativeUrlParamNames = parsePathParameters(value);
}
static Set<String> parsePathParameters(String path) {
    Matcher m = PARAM_URL_REGEX.matcher(path);
    Set<String> patterns = new LinkedHashSet<>();
    while (m.find()) {
    	patterns.add(m.group(1));
    }
    return patterns;
}
複製代碼

而後看看HTTP註解的解析過程,與GET相比起不一樣點只在於parseHttpMethodAndPath的方法入參都是從註解實例中取出,咱們能夠這麼定義HTTP註解

interface DoubanAPI {
    @HTTP(method = "GET", path = "v2/movie/in_theaters")
    fun inTheaters() : Call<ResponseBody>
}
複製代碼

接着看看Headers註解的解析,首先判斷了Headers註解的值是否設置,若是沒設置就拋出錯誤,而後調用parseHeaders進行解析

private Headers parseHeaders(String[] headers) {
    Headers.Builder builder = new Headers.Builder();
    for (String header : headers) {
        int colon = header.indexOf(':');
        if (colon == -1 || colon == 0 || colon == header.length() - 1) {
            throw methodError(method,
              "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
        }
        String headerName = header.substring(0, colon);
        String headerValue = header.substring(colon + 1).trim();
        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();
}
複製代碼

能夠看到parseHeaders內部其實就是根據冒號分割每一個字符串,而後將其放入到Header.Builder實例中統一管理,接下來看看方法參數的解析

2. 解析方法參數上的註解

RequestFactory.Builder的build方法中在解析完方法上面註解後,又會調用到parseParameter解析方法每一個參數上的註解,注意雖然每一個參數能夠有多少註解,可是每一個參數只能擁有一個Retrofit註解

// 其中p指代該參數是方法的第幾個參數,parameterTypes[p]表示當前參數的參數類型,
// parameterAnnotationsArray[p]表示當前參數的註解是個數組
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);

private ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations) {
    ParameterHandler<?> result = null;
    if (annotations != null) {
        for (Annotation annotation : annotations) {
            ParameterHandler<?> annotationAction =
                parseParameterAnnotation(p, parameterType, annotations, annotation);
            if (annotationAction == null) {
                continue;
            }
            if (result != null) {
                throw parameterError(method, p,
                  "Multiple Retrofit annotations found, only one allowed.");
            }
            result = annotationAction;
        }
    }
    // 方法的每一個參數都必須有且僅有一個Refrofit註解
    if (result == null) {
        throw parameterError(method, p, "No Retrofit annotation found.");
    }
    return result;
}
複製代碼

接着又調用到了parseParameterAnnotation這個方法很是長有400行左右,就不展開了只是說說其大概作了些什麼. 注意裏面判斷了一個不經常使用的註解@QueryName這個註解表示在Url後面拼加一個只有name沒有value的字符串

  • @Url,則須要確保如下幾點,最終會建立一個ParameterHandler.RelativeUrl實例返回
  1. 不能出現多個@Url註解
  2. @Url不能和@Path共存
  3. @Url不能聲明在@Query後
  4. @Url不能聲明在@QueryName後
  5. @Url不能聲明在@QueryMap後
  6. @Url使用了就不能再在請求方法後面加上相對地址
  7. 檢測參數類型必須是HttpUrl、String、URI、Uri中的一種否則拋出錯誤
  • @Path,則須要確保如下幾點,最終會建立一個ParameterHandler.Path實例返回
  1. @Path不能聲明在@Query後面
  2. @Path不能聲明在@QueryName後面
  3. @Path不能聲明在@QueryMap後面
  4. @Path不能和@Url共存
  5. @Path使用了就必需要在請求方法後面加上相對地址
  6. 剛纔解析方法上Url的時候會把全部{參數}解析出來放到relativeUrlParamNames這個Set中去,若是這個集合中不存在Path.value就會報錯
  • @Query,則會根據參數類型最終返回ParameterHandler.Query<>(name, converter, encoded).iterable()、ParameterHandler.Query<>(name, converter, encoded).array()、ParameterHandler.Query<>(name, converter, encoded)三者之一,就這告訴咱們@Query修飾的參數類型能夠是一個容器或者數組,以下所示

    interface DoubanAPI {
        @GET("v2/movie/in_theaters")
        fun inTheaters(@Query("keyword") List<String> keywords) : Call<ResponseBody>
    }
    val list = ArrayList<String>()
    list.add("keyword1")
    list.add("keyword2")
    val api = retrofit.create(DoubanAPI::class.java)
    val call = api.inTheaters(list)
    // 最終的url爲https://api.douban.com/v2/movie/in_theaters?keyword=keyword1&keyword=keyword2
    複製代碼
  • @QueryName,則會根據參數類型最終返回ParameterHandler.QueryName<>(converter, encoded).iterable()、ParameterHandler.QueryName<>(converter, encoded).array()、ParameterHandler.QueryName<>(converter, encoded)三者之一,跟@Query基本同樣

  • @QueryMap,首先會檢查下參數類型是不是Map,而後還會檢查下Map的key是不是String,最後會封裝成ParameterHandler.QueryMap返回

  • @Header,最終也會根據參數類型轉換爲ParameterHandler.Header<>(name, converter).iterable()、ParameterHandler.Header<>(name, converter).array()、ParameterHandler.Header<>(name, converter)之一,這裏也能看出@Header註解支持容器(內部類型要是String)或者數組

  • @HeaderMap,解析步驟和@QueryMap同樣,最後返回ParameterHandler.HeaderMap

  • @Field 首先會檢查是否已經設置了FormUrlEncoded,沒設置就報錯也會根據參數類型最後返回ParameterHandler.Field<>(name, converter, encoded).iterable()、ParameterHandler.Field<>(name, converter, encoded).array()、ParameterHandler.Field三者之一

  • @FieldMap 與@QueryMap判斷一致最後會返回一個ParameterHandler.FieldMap實例

  • @Part 首先檢查是否設置了Multipart註解,沒設置就報錯,而後判斷註解的value屬性是否爲空,接着根據類型返回ParameterHandler.RawPart.INSTANCE.iterable()、ParameterHandler.RawPart.INSTANCE.array()、ParameterHandler.RawPart.INSTANCE之一,若是value屬性不爲空會先添加幾個Header,而後根據類型返回ParameterHandler.Part<>(headers, converter).iterable()、ParameterHandler.Part<>(headers, converter).array()、ParameterHandler.Part<>(headers, converter)

  • @PartMap 與@QueryMap判斷基本一致,最終返回ParameterHandler.PartMap

  • @Body 若是設置了@FormUrlEncoded或者@Multipart就報錯,不然返回一個ParameterHandler.Body實例

至此方法上面和請求參數上面的註解已經都解析完畢了

HttpServiceMethod實例的生成

接着調用HttpServiceMethod.parseAnnotations獲取ServiceMethod實例將其放入到serviceMethodCache中

// HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) {
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
    Type responseType = callAdapter.responseType();
    if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError(method, "'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    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;
    return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
複製代碼

獲取CallAdapter實例

而後調用到了createCallAdapter用於獲取能處理該返回類型的CallAdapter

private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method) {
    Type returnType = method.getGenericReturnType();
    Annotation[] annotations = method.getAnnotations();
    try {
        return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
    } catch (RuntimeException e) {
        throw methodError(method, e, "Unable to create call adapter for %s", returnType);
    }
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
  Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");
    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;
        }
    }
    StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
        .append(returnType)
        .append(".\n");
    if (skipPast != null) {
        builder.append(" Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
        }
        builder.append('\n');
    }
    builder.append(" Tried:");
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
        builder.append("\n * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
}
複製代碼

能夠看出nextCallAdapter會在Retrofit的callAdapterFactories裏面遍歷查找能處理該返回類型的CallAdapter,而callAdapterFactories在文章一開始已經說過了API24及以上默認包含CompletableFutureCallAdapterFactoryDefaultCallAdapterFactory兩個CallAdapterFactory,也就是說默認方法返回值只能是CompletableFuture或者retrofit2.Call,其他都將報錯

獲取Converter實例

HttpServiceMethod.parseAnnotations後面接着又會調用createResponseConverter獲取Convert實例

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);
    }
}
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) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");
    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;
        }
    }
    StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
            .append(type)
            .append(".\n");
    if (skipPast != null) {
        builder.append(" Skipped:");
        for (int i = 0; i < start; i++) {
            builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
        }
        builder.append('\n');
    }
    builder.append(" Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        builder.append("\n * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
}
複製代碼

跟獲取CallAdapter流程基本同樣,其會在converterFactories裏面遍歷尋找是否有Convert能夠將ResponseBody轉化爲type類型,API>=24會默認擁有BuiltInConverters、OptionalConverterFactory兩個ConvertFactory,首先看看BuiltInConverters

BuiltInConverters
// BuiltInConverters.java
final class BuiltInConverters extends Converter.Factory {
    private boolean checkForKotlinUnit = true;
    @Override
    public @Nullable
    Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
        if (type == ResponseBody.class) {
            return Utils.isAnnotationPresent(annotations, Streaming.class)
                    ? StreamingResponseBodyConverter.INSTANCE
                    : BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        if (checkForKotlinUnit) {
            try {
                if (type == Unit.class) {
                    return UnitResponseBodyConverter.INSTANCE;
                }
            } catch (NoClassDefFoundError ignored) { 
                checkForKotlinUnit = false;
            }
        }
        return null;
    }
}
static final class StreamingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final StreamingResponseBodyConverter INSTANCE = new StreamingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) {
        return value;
    }
}
static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            // 所有讀入內存
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}
static ResponseBody buffer(final ResponseBody body) throws IOException {
    Buffer buffer = new Buffer();
    // 將body的內容所有讀入到buffer中去
    body.source().readAll(buffer);
    return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}
static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
        static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();
    @Override
    public Void convert(ResponseBody value) {
        value.close();
        return null;
    }
}
複製代碼
  • 若是目標轉化類型爲ResponseBody而且方法上有@Stream註解,那麼會原封不動的返回
  • 若是目標轉化類型爲ResponseBody而且方法上沒有@Stream註解,那麼會將ResponseBody整個讀入內存(注意當文件過大可能會OOM)
  • 若是目標轉化類型爲Void,那麼將ResponseBody直接關閉,外界拿到的響應體就是null
  • 若是目標轉化類型爲Unit,那麼跟Void同樣
OptionalConverterFactory
final class OptionalConverterFactory extends Converter.Factory {
    static final Converter.Factory INSTANCE = new OptionalConverterFactory();
    @Override
    public @Nullable
    Converter<ResponseBody, ?> responseBodyConverter(
            Type type, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(type) != Optional.class) {
            return null;
        }
        Type innerType = getParameterUpperBound(0, (ParameterizedType) type);
        Converter<ResponseBody, Object> delegate =
                retrofit.responseBodyConverter(innerType, annotations);
        return new OptionalConverter<>(delegate);
    }
}
複製代碼

很明顯只能轉化爲Optional,而且若是是Optional還會再檢查其持有類型,至此經過requestFactory(解析註解獲取)、CallAdapter(根據方法返回值尋找)、Convert(根據將ResponseBody轉化爲指定類型尋找)、Call.Factory(默認設置是新建的OkHttpClient實例,能夠傳入本身的Call.Factory)構建出HttpServiceMethod實例,而後將其放入serviceMethodCache中,到此eagerlyValidateMethods分析完畢,接着回到retrofit.create方法

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();
                private final Object[] emptyArgs = new Object[0];
                @Override
                public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
                    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);
                }
            });
}
複製代碼

這裏就是一個動態代理,當調用create方法返回的實例的任何方法都會直接回調invoke方法。

4、api.inTheater方法的調用

上述動態代理內部判斷若是調用的方法來自Object那麼直接調用,若是調用的是默認方法在Android中會直接拋出錯誤,此外就去獲取ServiceMethod實例調用其invoke方法,因爲咱們剛纔已經把全部ServiceMethod都放入到了serviceMethodCache中所以直接取出執行就好了。接着看HttpServiceMethod的invoke方法

// HttpServiceMethod.java
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
    new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
複製代碼

若是按照本文剛開始的例子那麼callAdapter由DefaultCallAdapterFactory.get獲取

public @Nullable 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 call;
        }
    };
}
複製代碼

相對於直接返回給外界了一個OkHttpCall實例,繼續看看該類的execute方法

public Response<T> execute() throws IOException {
        okhttp3.Call call;
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already executed.");
        executed = true;
        if (creationFailure != null) {
            if (creationFailure instanceof IOException) {
                throw (IOException) creationFailure;
            } else if (creationFailure instanceof RuntimeException) {
                throw (RuntimeException) creationFailure;
            } else {
                throw (Error) creationFailure;
            }
        }
        call = rawCall;
        if (call == null) {
            try {
                call = rawCall = createRawCall();
            } catch (IOException | RuntimeException | Error e) {
                throwIfFatal(e); // Do not assign a fatal error to creationFailure.
                creationFailure = e;
                throw e;
            }
        }
    }
    if (canceled) {
        call.cancel();
    }
    return parseResponse(call.execute());
}
複製代碼

這個OkHttpCall與RealCall一致都只能被執行一次,先不去管響應,接着調用createRawCall建立RealCall實例

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;
}
複製代碼

這裏的callFactoty通常也就是一個OkHttpClient實例,來看看requestFactory.create是如何建立一個Request實例

okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
            ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
    int argumentCount = args.length;
    if (argumentCount != handlers.length) {
        throw new IllegalArgumentException("Argument count (" + argumentCount
                + ") doesn't match expected count (" + handlers.length + ")");
    }
    // 將經過註解解析到的內容加入到RequestBuilder中
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
            headers, contentType, hasBody, isFormEncoded, isMultipart);
    List<Object> argumentList = new ArrayList<>(argumentCount);
    // 調用每一個ParameterHandler實例的apply方法
    for (int p = 0; p < argumentCount; p++) {
        argumentList.add(args[p]);
        handlers[p].apply(requestBuilder, args[p]);
    }
    return requestBuilder.get()
            .tag(Invocation.class, new Invocation(method, argumentList))
            .build();
}
複製代碼

inTheaters方法有一個參數,根據上述源碼咱們知道其會建立一個ParameterHandler.Query實例,看看其apply方法

// 這裏的valueConverter實際上是遍歷了converterFactories而後調用stringConverter,若是咱們沒設置那麼默認
// valueConverter就是BuiltInConverters裏面的ToStringConverter實例
static final class Query<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;
    Query(String name, Converter<T, String> valueConverter, boolean encoded) {
        this.name = checkNotNull(name, "name == null");
        this.valueConverter = valueConverter;
        this.encoded = encoded;
    }
    @Override
    void apply(RequestBuilder builder, @Nullable T value) throws IOException {
        if (value == null) return; // Skip null values.
        String queryValue = valueConverter.convert(value);
        if (queryValue == null) return; // Skip converted but null values
        builder.addQueryParam(name, queryValue, encoded);
    }
}
static final class ToStringConverter implements Converter<Object, String> {
    static final ToStringConverter INSTANCE = new ToStringConverter();
    @Override
    public String convert(Object value) {
        return value.toString();
    }
}
複製代碼

很明顯ParameterHandler.Query只是添加了一個請求參數,接着調用requestBuilder.get去真正的建立 okhttp3.Request.Builder實例

Request.Builder get() {
    HttpUrl url;
    HttpUrl.Builder urlBuilder = this.urlBuilder;
    if (urlBuilder != null) {
        url = urlBuilder.build();
    } else {
        // 組合Url
        url = baseUrl.resolve(relativeUrl);
        if (url == null) {
            throw new IllegalArgumentException(
                    "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
        }
    }
    RequestBody body = this.body;
    if (body == null) {
        if (formBuilder != null) {
            body = formBuilder.build();
        } else if (multipartBuilder != null) {
            body = multipartBuilder.build();
        } else if (hasBody) {
            body = RequestBody.create(null, new byte[0]);
        }
    }
    MediaType contentType = this.contentType;
    if (contentType != null) {
        if (body != null) {
            body = new ContentTypeOverridingRequestBody(body, contentType);
        } else {
            requestBuilder.addHeader("Content-Type", contentType.toString());
        }
    }
    return requestBuilder
            .url(url)
            .method(method, body);
}
複製代碼

至此建立Request實例成功,接着調用了call.execute方法執行網絡請求,接下來看看其是如何解析響應的

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
        ResponseBody rawBody = rawResponse.body();
    // 首先移除了響應體,以便於長時間保存Response
    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();
        // 20四、205無響應體封裝成一個成功的響應
        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;
    }
}
複製代碼

最終調用responseConverter的convert方法將ResponseBody實例轉化爲指定的類型,因爲本例中inTheaters方法返回值爲Call<ResponseBody>,所以這裏的T就是ResponseBody類型,而responseConverter就是BufferingResponseBodyConverter實例

static final class BufferingResponseBodyConverter implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();
    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}
複製代碼

內部直接將全部ResponseBody所有讀入內存,而後新建一個Response實例返回,parseResponse最後再調用Response.success構造一個成功的響應返回給外界,至此Retrofit的基本工做流程已經梳理完畢。下面來看看CallAdapter和Convert的做用

5、CallAdapter、Converter的做用

首先看看CallAdapter,下面是它的接口定義

public interface CallAdapter<R, T> {

    // 返回一個代理了call的實例,不須要代理就原樣返回好了
    T adapt(Call<R> call);
    
    // 返回T所對應的類型,{@code Call<Repo>} is {@code Repo}
    Type responseType();
    
    abstract class Factory {
        // 返回一個能處理接口返回類型的CallAdapter,若是不能處理該類型就返回null
        public abstract @Nullable
        CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
                              Retrofit retrofit);
                              
        // 提取指定index位置泛型參數類型的上界
        // index 1 of {@code Map<String, ? extends Runnable>} returns {@code Runnable}.
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }
        // 獲取原始的類型 {@code List<? extends Runnable>} returns {@code List.class}.
        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}
複製代碼

在建立HttpServiceMethod的時候會遍歷全部的CallAdapter.Factory並調用其get方法,一旦某個CallAdapter.Factory的get方法不返回null就中止遍歷,若是全部的都返回null,那麼會報錯。若是成功返回CallAdapter實例callAdapter,那麼接着調用callAdapter的responseType方法獲取到泛型類型,接着根據這個泛型類型去ConvertFactory列表中尋找能夠將ResponseBody轉化爲該泛型類型的Converter。最後在內部建立OkHttpCall後會調用adapt方法。總結下就是在get方法中判斷returnType是否能處理,若是能處理的話,adapt方法必需要將call轉化爲returnbType類型的實例,接着看看Converter,下面是它的定義

public interface Converter<F, T> {
    @Nullable
    T convert(F value) throws IOException;
    abstract class Factory {
        // 返回一個能將ResponseBody轉化爲type類型的Converter,若是不能轉換那麼返回null
        public @Nullable
        Converter<ResponseBody, ?> responseBodyConverter(Type type,
            Annotation[] annotations, Retrofit retrofit) {
            return null;
        }
        // 返回一個能將type類型轉換爲RequestBody類型的Converter,若是不能轉換那麼返回null
        // 只在擁有@Body或者@Part或者@PartMap時纔會調用
        public @Nullable
        Converter<?, RequestBody> requestBodyConverter(Type type,
            Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
            return null;
        }
        // 返回一個能將制定類型轉換爲字符串的Converter,只在擁有如下註解時纔會調用
        // @Field、@FieldMap、@Header、@HeaderMap、@Path、@Query、@QueryMap
        Converter<?, String> stringConverter(Type type, Annotation[] annotations,
                                             Retrofit retrofit) {
            return null;
        }
        // 這兩個方法與CallAdapterFactory一致
        protected static Type getParameterUpperBound(int index, ParameterizedType type) {
            return Utils.getParameterUpperBound(index, type);
        }
        protected static Class<?> getRawType(Type type) {
            return Utils.getRawType(type);
        }
    }
}
複製代碼

Converter.Factory提供了responseBodyConverter、requestBodyConverter、stringConverter三個重要方法,分別用於將ResponseBody轉換爲指定類型、將指定類型轉換爲RequestBody、將指定類型轉換爲String。三個方法都返回值都是一個Converter實例其只有一個方法convert方法內部作轉換操做,下面爲了加深理解咱們來看看GsonConverterFactory的源碼

public final class GsonConverterFactory extends Converter.Factory {
    public static GsonConverterFactory create() {
        return create(new Gson());
    }
    public static GsonConverterFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new GsonConverterFactory(gson);
    }
    private final Gson gson;
    private GsonConverterFactory(Gson gson) {
        this.gson = gson;
    }
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonResponseBodyConverter<>(gson, adapter);
    }
    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new GsonRequestBodyConverter<>(gson, adapter);
    }
}

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實例,而後調用read轉換爲指定類型的實例
        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();
        }
    }
}
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

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

    @Override
    public RequestBody convert(T value) throws IOException {
        // 獲取輸出流構建成JsonWrite實例,而後調用write方法寫入buffer中
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}
複製代碼

6、總結

Retrofit的工做流程主要包括解析註解、動態代理、Request的生成、Response的解析四個大步驟,內部默認仍是使用了OkHttp進行網絡請求,其中前兩步順序可能會相反這取決於validateEagerly是否爲true,Request的生成和Response的解析依賴於CallAdapterFactory和ConverterFactory。

相關文章
相關標籤/搜索