經過源碼全面解剖Retrofit2的總體流程

前言

上兩篇文章:java

Retrofit與Okhttp是Android開發中最最熱門的網絡請求庫,它們都來自square公司,Okhttp在前面的兩篇文章中已經經過源碼從請求流程和攔截器兩個角度分析過,本文的主角是Retrofit,通過這幾天的研究,我發現Retrofit只是一個對Okhttp網絡請求框架的巧妙包裝,它經過註解去定義一個HTTP請求,而後在底層經過Okhttp發起網絡請求,就是這樣的一個簡單的過程,其間運用了不少的設計模式:外觀模式、動態代理模式、適配器模式、裝飾者模式等,其最核心的是動態代理模式,因此在此以前你們對動態代理要有一個瞭解:android

靜態和動態代理模式git

其餘的設計模式我會在講解的過程當中簡單介紹,除了使用了大量的設計模式,Retrofit還應用了面向接口編程的思想,使得整個系統解耦完全,本文會經過一個簡單的Retrofit使用示例,而後引出Retrofit的核心類,面向接口思想、構建過程、動態代理和網絡請求過程,經過這幾部分來解剖Retrofit。github

Retrofit的項目地址:Retrofit編程

本文源碼基於Retrofit2.4json

1、Retrofit的簡單使用

首先來回憶一下Retrofit的使用,我這裏使用的是Github平臺的開放api,這個api根據用戶名獲取一個用戶信息,首先在你的AndroidManifest.xml中聲明網絡權限,而後:設計模式

一、建立一個Api接口api

public interface GithubService {

    @GET("users/{user}")
    Call<ResponseBody> getUserInfo(@Path("user") String user);

}
複製代碼

我用Retrofit的註解聲明瞭一個GET請求的方法,Call是Retrofit中的Call,而不是Okhttp中的Call,而ResponseBody是Okhttp的ResponseBody。數組

二、建立Retrofit實例緩存

Retrofit Retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
複製代碼

使用Builder模式構建Retrofit實例,傳入baseUrl,咱們日常開發通常會添加Rxjava2CallAdapterFactory和GsonConverterFactory,但這裏我沒有使用addCallAdapterFactory(Factory)來添加CallAdapterFactory,也沒有使用addConverterFactory(Factory)來添加ConverterFactory,都使用默認的CallAdapter和Converter,默認的CallAdapter返回的就是Retrofit中的Call類型,默認的Converter會把網絡請求返回數據轉化爲Okhttp中的ResponseBody,這也就是我上面定義接口時,Cal的T是ResponseBody的緣由。

三、建立Api接口實例

GithubService service = Retrofit.create(GithubService.class);
複製代碼

經過Retrofit實例的create方法建立Api接口實例GithubService。

四、調用Api接口的方法,生成Call

Call<ResponseBody> call = service.getUserInfo("rain9155");
複製代碼

調用Api接口的方法,會返回一個Call實例。

五、經過Call發起同步或異步請求,而後獲取返回結果Response

//同步請求
Response<ResponseBody> response = call.execute();
或
//異步請求 
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response){
            	//經過Response獲取網絡請求返回結果
                ResponseBody body = response.body();
                try {
                    Log.d(TAG, "請求結果:" +  body.string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

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

            }
        });
複製代碼

經過Call的execute或enqueue方法發起網絡請求,當網絡請求結果返回時,就能夠經過Response的body方法獲取,這裏由於使用默認的Converter,因此獲取到的body的是Okhttp的ResponseBody,log的輸出結果是JSON數據

這就是Retrofit發起網絡請求的五步曲,若是除去第一步,和Okhttp的使用仍是很是的類似的,由於Retrofit和Okhttp的類名有不少的重複,下面若是涉及Okhttp的相關類,我會特別說明,不然默認都是屬於Retrofit的。

2、Retrofit的相關類介紹

先簡單的介紹一下重要的類,會對後面的閱讀有幫助,當咱們把Retrofir的源碼clone下來,發現裏面有4個主要的模塊,分別是:

  • retrofit-adapter
  • retrofit-converters
  • retrofit-mock
  • retrofit

其中retrofit-mock是測試時用的,不關咱們的事,和咱們開發相關的是retrofit-adapter、retrofit-converters和retrofit模塊,當咱們沒有使用外置的CallAdapter和Converters時,咱們只須要依賴retrofit模塊,retrofit模塊中有3個很是重要的接口,分別是:

  • Call: 網絡請求執行器,用於執行同步或異步的網絡請求,內部最終經過Okhttp的Call發起網絡請求
  • CallAdapter:網絡請求適配器,它用於把默認的網絡請求執行器的調用形式,適配成在不一樣平臺下的網絡請求執行器的調用形式,例如Retrofit默認經過Call,內部使用ExecutorCallbackCall經過handler來執行網絡請求後的線程切換,經過添加RxjavaCallAdapter後,RxjavaCallAdapter把默認的網絡請求執行器適配成Observerable或Flowable,這樣我可使用Rxjava的鏈式調用方式來執行網絡請求後的線程切換。
  • Converter:數據轉化器,兩個方向的轉化,把Api接口方法的參數註解的值轉化爲網絡請求執行器須要的數據類型,和把網絡返回的數據轉化爲咱們須要的數據類型。

還有一個Callback接口,用於回調網絡請求成功或失敗,很簡單,就不介紹了,其中CallAdapter和Converter內部都有一個Factory類,它都是經過工廠模式建立,工廠模式就是將複雜對象的實例化任務交給一個類去實現,使得使用者不用知道具體參數就能夠實例化出所須要的對象,在Retrofit中,想要得到CallAdapter或Converter的實例都須要經過Factory來獲取。下面分別簡單的介紹一下Call、CallAdapter和Converter接口的做用和在Retrofit下的默認實現。

一、Call

網絡請求執行器,用於執行同步或異步的網絡請求,Call接口以下:

public interface Call<T> extends Cloneable {
  
  //發起同步請求,返回Response
  Response<T> execute() throws IOException;

  //發起異步請求,使用callback把Response回調出去
  void enqueue(Callback<T> callback);

 //當執行了execute或enqueue後,該方法返回true
  boolean isExecuted();
    
  //取消此次網絡請求
  void cancel();

  //當執行了cancel()後,這個方法返回true
  boolean isCanceled();

  //clone一個Call
  Call<T> clone();

  //返回HTTP網絡請求,這個Request是來自okhttp的
  Request request();
}

複製代碼

Retrofit的Call和Okhttp的Call接口定義的方法差很少,只是多了一個clone方法,在Retrofit中,Call的默認實現類是OkHttpCall,以下:

final class OkHttpCall<T> implements Call<T> {
    private final ServiceMethod<T, ?> serviceMethod;//這個ServiceMethod很重要,它封裝了Api接口方法中的註解和參數信息,一個ServiceMethod對應一個Method(在建立Api接口實例會講到)

    private final @Nullable Object[] args;//表明着Api接口方法中的參數

    private @Nullable okhttp3.Call rawCall;//這是一個來自Okhttp的Call

    private @Nullable Throwable creationFailure;
    private boolean executed;
    private volatile boolean canceled;

    Override public Response<T> execute() throws IOException {
        okhttp3.Call call;
        //...
        call = rawCall;
        return parseResponse(call.execute());
    }
    
    @Override 
    public void enqueue(final Callback<T> callback) {
        okhttp3.Call call;
        call = rawCall;
		//...
        call.enqueue(new okhttp3.Callback() {
            @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                //...
                callback.onResponse(OkHttpCall.this, response);
            }

            @Override public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
            }
        });
    }
    
    //...
}
複製代碼

一個OkHttpCall實例就表明着一次網絡請求,OkHttpCall裏面大部分方法的邏輯都是轉發給Okhttp的Call方法。

在本文,無論來自Okhttp的Call,仍是來自Retrofit的Call,均可以理解爲網絡請求執行器。

二、CallAdapter

網絡請求適配器,用於把默認的網絡請求執行器的調用形式,適配成在不一樣平臺下的網絡請求執行器的調用形式,CallAdapter接口以下:

public interface CallAdapter<R, T> {
  
  //返回響應body轉換爲Java對象時使用的類型
  //例如Call<ResponseBody>, Type就是ResponseBody,Type是來自java.lang.reflect包的
  Type responseType();

  //把Call<R>適配成 T 類型,就是將Retrofit的Call適配成另一個T類型的'Call'
  T adapt(Call<R> call);

  //用於建立CallAdapter實例,經過get方法能夠返回一個CallAdapter實例或null
  abstract class Factory {
    
    //根據Api接口定義的方法的返回值和註解信息,建立一個CallAdapter實例返回,若是這個Factory不能處理這個方法的返回值和註解信息,返回null,
    //注意這裏的returnType != 上面的responseType,例如Call<ResponseBody>,returnType的Type就是Call
    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit Retrofit);

    //返回ParameterizedType的上限,即泛型類型的上限
    //例如Call<? extends ResponseBody>, Type就是ResponseBody
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

   //返回Type的原始類型
   //例如Type爲Call<ResponseBody>,返回Call.class
    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}
複製代碼

CallAdapter接口很簡單,只有兩個方法responseType和adapt方法,和一個Factory類,其中Factory類的get方法能夠獲取一個CallAdapter示例,CallAdapter的responseType方法就是得到Call中的T類型,這個Call就是咱們在定義Api接口方法時方法的返回參數,CallAdapter的adapt方法用於把傳入的Call適配成另一個咱們所期待的'Call',這裏使用到了適配器模式,適配器模式就是在兩個因接口不兼容的類之間加一個適配器,將一個類的接口變成客戶端所期待的另外一種接口,從而使得它們工做在一塊兒,至於怎麼適配就須要看適配器中得adapt方法的實現,接下來咱們看adapt方法在Retrofit中的默認實現。(在Android Platform下的默認實現,Platform的概念在構建過程當中會講到)

在Retrofit中,CallAdapter的默認實現是一個匿名類,能夠經過CallAdapter的Factory得到,CallAdapter的Factory的默認實現是ExecutorCallAdapterFactory,以下:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    
  //線程切換執行器(在Retrofit的建立過程當中會講)
  final Executor callbackExecutor;

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

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit Retrofit) {
      if (getRawType(returnType) != Call.class) {
          return null;
      }
      //能夠經過returnType得到responseType
      //由於returnType = Call<T>, 有了Call<T>, 固然能夠得到Call中的T,而T就是responseType
      final Type responseType = Utils.getCallResponseType(returnType);
      //返回一個CallAdapter匿名類
      return new CallAdapter<Object, Call<?>>() {

          @Override 
          public Type responseType() {
              //返回responseType
              return responseType;
          }

          @Override 
          public Call<Object> adapt(Call<Object> call) {
              //默認CallAdapter的adapt方法返回
              return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
      };
  }
  
 //網絡請求執行器(在建立Api接口實例中會講)
 static final class ExecutorCallbackCall<T> implements Call<T> {
     //...
  }  
    
}
複製代碼

在ExecutorCallAdapterFactory的get方法中,new了一個CallAdapter返回,在CallAdapter的adapt方法實現中,new了一個ExecutorCallbackCall返回,並把入參call和callbackExecutor傳進了ExecutorCallbackCall的構造中,ExecutorCallbackCall就是一個實現了Call接口的類,仍是一個Call,它就是Retrofit的默認網絡請求執行器,能夠看到Retrofit的默認的網絡請求執行器適配,即adapt方法的默認實現就是用ExecutorCallbackCall包裝傳進來的Call,並返回ExecutorCallbackCall,這個傳進來的Call就是Call的默認實現OkHttpCall,待會在Retrofit的構建過程當中還會講到。

既然CallAdapter能把默認的網絡請求執行器的調用形式,適配成在不一樣平臺下的網絡請求執行器的調用形式,那麼它支持哪些平臺呢?這個在retrofit-adapter 模塊中能夠找到答案,以下:

Retrofit還支持guava、java八、rxjava、scala這四個平臺,它們裏面都各自實現了retrofit模塊暴露出去的CallAdapter接口和CallAdapter接口中的Factory接口,在CallAdapter的adapt方法中提供各自平臺的適配,咱們能夠經過addCallAdapterFactory(Factory)來添加不一樣平臺的CallAdapter工廠。

三、Converter

數據轉化器,把咱們在Api接口定義的方法註解和參數轉化爲網絡請求執行器須要的請求類型,和把網絡返回的數據轉化爲咱們須要的數據類型,Converter接口以下:

public interface Converter<F, T> {
   
  //把F 轉化爲 T,用於在網絡請求中實現對象的轉化
  T convert(F value) throws IOException;

  //經過Factory的responseBodyConverter或requestBodyConverter方法得到一個Converter實例或null
  abstract class Factory {
    
    //返回一個處理網絡請求響應(Response)的body的Converter實例,若是不能處理這些類型(type)和註解,返回null
    //這個Converter會把 ResponseBody 轉化成 ?,這個ResponseBody是來自okhttp的
    //例如使用GsonConverter,?表明某個java對象類型
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
        Annotation[] annotations, Retrofit Retrofit) {
      return null;
    }

    //返回一個處理網絡請求(Request)的body的Converter實例,若是不能處理這些類型(type)和註解,返回null
    //這個Converter會把 ?轉化成 RequestBody,這個RequestBody是來自okhttp的
    //這個Converter主要處理@Body、 @Part、@PartMap類型的註解
    public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
        Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit Retrofit) {
      return null;
    }

    //返回一個處理網絡請求(Request)的body的Converter實例
    //這個Converter會把 ?轉化成 String
    //這個Converter主要處理@Field、@FieldMap、@Header、HeaderMap @HeaderMap、@Path、@Query、@QueryMap類型的註解
    public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
        Retrofit Retrofit) {
      return null;
    }

    //下面兩個方法和上面CallAdapter的Factory中同名方法的意思同樣
  
    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

複製代碼

Converter接口也很簡單,只有一個convert方法,和一個Factory類,由於Converter要提供兩個方向的轉化,因此Factory類就提供了兩個方法用於獲取不一樣方向的轉化,其中responseBodyConverter方法就是得到一個把網絡返回的數據轉化爲咱們須要的數據類型的Converter實例,而requestBodyConverter方法就是得到一個把咱們在Api接口定義的方法註解和參數轉化爲網絡請求的Converter實例,那麼要怎麼轉化呢?就要看Converter的convert方法的實現,convert方法把F類型 轉化爲 T類型,接下來咱們看convert方法在Retrofit中的默認實現。

Converter在Retrofit的默認實現有五個,都是Converter的Factory的內部類,可經過Converter的Factory得到,Converter的Factory的默認實現是BuiltInConverters,以下:

final class BuiltInConverters extends Converter.Factory {
    
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit Retrofit) {
    if (type == ResponseBody.class) {//支持ResponseBody類型的轉化
      
      //若是是二進制流形式,就返回StreamingResponseBodyConverter實例
      //若是是字符流形式,就返回BufferingResponseBodyConverter實例
      return Utils.isAnnotationPresent(annotations, Streaming.class)
          ? StreamingResponseBodyConverter.INSTANCE
          : BufferingResponseBodyConverter.INSTANCE;
    }
    if (type == Void.class) {//支持Void類型的轉化
        
      //返回VoidResponseBodyConverter實例
      return VoidResponseBodyConverter.INSTANCE;
    }
      
    //除了以上兩種類型,其餘類型都不支持,返回null
    return null;
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit Retrofit) {
    //支持向RequestBody類型轉化
    if (RequestBody.class.isAssignableFrom(Utils.getRawType(type))) {
        
      //返回RequestBodyConverter實例
      return RequestBodyConverter.INSTANCE;
    }
    
    //除了RequestBody類型,不支持向其餘類型轉化,返回null
    return null;
  }

   static final class VoidResponseBodyConverter implements Converter<ResponseBody, Void> {
    static final VoidResponseBodyConverter INSTANCE = new VoidResponseBodyConverter();

    @Override public Void convert(ResponseBody value) {
      value.close();
      return null;
    }
  }

  static final class RequestBodyConverter implements Converter<RequestBody, RequestBody> {
    static final RequestBodyConverter INSTANCE = new RequestBodyConverter();

    @Override public RequestBody convert(RequestBody value) {
      return value;
    }
  }

  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 {
        // Buffer the entire body to avoid future I/O.
        return Utils.buffer(value);
      } finally {
        value.close();
      }
    }
  }

  static final class ToStringConverter implements Converter<Object, String> {
    static final ToStringConverter INSTANCE = new ToStringConverter();

    @Override public String convert(Object value) {
      return value.toString();
    }
  }
}

複製代碼

BuiltInConverters實現了Factory中的responseBodyConverter和requestBodyConverter方法,內部含有五個Converter默認實現類,在Factory的responseBodyConverter和requestBodyConverter方法中分別返回這幾Converter實例,其中只有ToStringConverter沒有使用到,咱們還發現了這五個Converter的convert方法的實現除了BufferingResponseBodyConverter,大部分都是,入參是是什麼,返回就是什麼,因此Retrofit中Converter默認實現的convert方法大部分都沒有對數據進行轉化,返回原始數據,這些原始數據是String或來自Okhttp的ResponseBody、RequestBody,例如ResponseBodyConverter的convert方法就是返回Okhttp的ResponseBody,RequestBodyConverter的convert方法就是返回Okhttp的RequestBody。

Converter除了默認的返回原始數據,它還支持哪些數據轉化呢?這個在retrofit-converters模塊中能夠找到答案,以下:

能夠看到Retrofit還支持json、xml、protobuf等多種數據類型的轉化,這些子模塊都各自實現了retrofit模塊暴露出來的Converter接口和Converter接口中的Factory接口,在Converter的adapt方法中實現不一樣數據類型的轉化邏輯,咱們能夠經過addConverterFactory(Factory)來支持不一樣數據類型轉化的Converter工廠。

四、面向接口設計

在retrofit模塊中提供了Call、Callback、CallAdapter、Converter接口供外部模塊使用,CallAdapter和Converter接口中還有相應的Factory接口,各模塊以前經過接口依賴主模塊Retrofit,將網絡請求、網絡請求適配、請求處理與返回解析徹底解耦,當須要修改Retrofit中的默認實現時,只須要add一個外部模塊提供的工廠,具體建立什麼樣的實例由工廠方法來負責,這樣就能以最小的代價(不須要改動代碼)換成其餘模塊上的實現,Retrofit自己並不參與這個過程,它只是負責提供一些主要的參數供它們進行決策,以及進行參數的處理,模塊之間依賴於接口,而不依賴於具體的實現,這是一種很好的編程思路,面向接口編程。

面向接口編程:也被熟知爲基於接口的設計,是一種基於組件級別的,面嚮對象語言的模塊化編程設計實現,面向接口編程是面向對象編程的一種模塊化實現形式,理論上說具備對象概念的程序設計均可以稱之爲面向對象編程,而面向接口編程則是從組件的級別來設計代碼,將抽象與實現分離。

好了,在簡單的瞭解了一下待會和構建過程涉及到的相關類,接下來分析Retrofit的構建過程。

3、Retrofit的建立過程

Retrofit Retrofit = new Retrofit.Builder()//一、構造Builder
    .baseUrl("https://api.github.com/")//二、配置Builder
    .build();//三、建立Retrofit實例
複製代碼

Retrofit是使用Builder模式構建出一個Retrofit實例的,Builder模式的好處就是將一個複雜對象的構建和它的表示分離,在用戶在不知道內部構建細節的狀況下,能夠更加精準的控制對象的構造過程,因此咱們直接看Retrofit的內部類Builder就行,由於在Builder中配置的字段最終都在build時賦值給Retrofit中相應的字段,Builder只是暫時保存這些配置字段而已,下面咱們分註釋的3步去看Retrofit的Builder.

一、構造Builder

Builder類以下:

//Retrofit.java
public static final class Builder {

     private final Platform platform;//Retrofit運行的平臺
     //...

     //根據Platform構造
     Builder(Platform platform) {
         this.platform = platform;
     }

     public Builder() {
         //調用Platform的get方法獲取一個Platform
         this(Platform.get());
     }

     //根據另一個Retrofit構造
     Builder(Retrofit Retrofit) {
         platform = Platform.get();
         callFactory = Retrofit.callFactory;
         baseUrl = Retrofit.baseUrl;
         //...
     }

   //...
  }
複製代碼

new Retrofit.Builder(),咱們使用了無參的構造函數來建立Builder,Builder的無參構造函數首先經過**Platform.get()**獲取了一個Platform實例賦值給了platform字段,前面提到過Retrofit是有Platform的概念,Retrofit支持java和Android平臺,咱們來看一下Platform這個類,以下:

class Platform {   
    //單例
    private static final Platform PLATFORM = findPlatform();

    //get方法
    static Platform get() {
        //返回Platform實例
        return PLATFORM;
    }

    private static Platform findPlatform() {
        
        try {
            //android.os.Build這個類是Android獨有的
            //這裏要求JVM查找並加載Build.class對象
            Class.forName("android.os.Build");
            if (Build.VERSION.SDK_INT != 0) {
                //若是是Android平臺,建立一個Android實例返回,Android繼承自Platform
                return new Android();
            }
        } catch (ClassNotFoundException ignored) {
            //找不到android.os.Build,會拋出異常,捕捉,繼續執行
        }
        
        try {
            //java.util.Optional這個類是java8以後纔有的,是java獨有的
            Class.forName("java.util.Optional");
            //建立一個Java8實例返回,Java8繼承自Platform
            return new Java8();
        } catch (ClassNotFoundException ignored) {
            //找不到java.util.Optional,會拋出異常,捕捉,繼續執行
        }
        
        //返回默認Platform實例
        return new Platform();
    }

    //返回默認的線程切換執行器
    Executor defaultCallbackExecutor() {
        return null;
    }
    
    //返回默認的網絡請求適配器工廠
    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
            return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        return DefaultCallAdapterFactory.INSTANCE;
    }

    boolean isDefaultMethod(Method method) {
        return false;
    }

    @Nullable Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object, @Nullable Object... args) throws Throwable {
        throw new UnsupportedOperationException();
    }

    @IgnoreJRERequirement // Only classloaded and used on Java 8.
    static class Java8 extends Platform {
        //...
    }

    static class Android extends Platform {
        //...
    }
}

複製代碼

首先Platform的get方法經過單例模式返回了一個Platform實例,單例模式就是保證單例對象的類在同一進程中,只有一個實例存在,Platform實例經過findPlatform方法建立,能夠看到findPlatform方法裏面區分了Android、java和其餘平臺返回了不一樣的Platform實現,因爲我這裏是Android平臺,只關注Android平臺的實現,Android類以下:

//Platform.java
static class Android extends Platform {

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

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

    //線程切換執行器
    static class MainThreadExecutor implements Executor {
        //構造Handler時經過Looper.getMainLooper()來構造
        //因此Handler的消息都會執行在主線程
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override public void execute(Runnable r) {
            handler.post(r);
        }
    }
}
複製代碼

Android繼承自Platform,重寫了它其中的兩個方法:defaultCallbackExecutor方法和defaultCallAdapterFactory方法,defaultCallbackExecutor方法返回了一個MainThreadExecutor,它是一個Executor,它的execute方法的實現就是簡單經過Handler把任務Runnable切換回主線程執行,就是說,線程池會把每個線程提交的任務都切回主線程執行,咱們再來看defaultCallAdapterFactory方法,這個方法返回了咱們上面介紹過的ExecutorCallAdapterFactory,並把callbackExecutor傳了進去,其實這個callbackExecutor就是MainThreadExecutor,待會在第3步構建Retrofit實例時就會講到。

這裏咱們來小結一下:

new Retrofit.Builder()裏面會經過Platform的get方法來獲取一個Platform實例,在Android中,它會返回Android平臺實例,這樣就指定了Retrofit的運行平臺是Android,而後就能夠經過Android平臺實例的defaultCallbackExecutor方法返回一個線程切換執行器MainThreadExecutor,它用於把任務切換回主線程執行,和經過defaultCallAdapterFactory方法返回一個網絡請求適配器工廠ExecutorCallAdapterFactory,工廠中持有一個線程切換執行器實例,經過工廠就能夠獲取網絡請求適配器實例。

有了Builder實例後,下面開始配置Builder.

二、配置Builder

//Retrofit.java
public static final class Builder {
    
    private final Platform platform;//Retrofit運行的平臺
    private @Nullable okhttp3.Call.Factory callFactory;//網絡請求執行器工廠,用建立網絡請求執行器實例,來自okhttp, 不是Retrofit中的那個Call
    private HttpUrl baseUrl;//網絡請求的Url地址
    private final List<Converter.Factory> converterFactories = new ArrayList<>();//數據轉化器工廠列表
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();//網絡請求適配器工廠列表
    private @Nullable Executor callbackExecutor;//線程切換執行器
    private boolean validateEagerly;//標誌位,是否提早對serviceMethod進行緩存(在建立Api接口實例會講到)
    
    //...
    
     //咱們傳入的String類型的Url,最終仍是會解析成HttpUrl類型,它是Retrofit中url的表明
    public Builder baseUrl(String baseUrl) {
        checkNotNull(baseUrl, "baseUrl == null");
        HttpUrl httpUrl = HttpUrl.parse(baseUrl);
        if (httpUrl == null) {
            throw new IllegalArgumentException("Illegal URL: " + baseUrl);
        }
        return baseUrl(httpUrl);
    }

   
    public Builder baseUrl(HttpUrl baseUrl) {
        checkNotNull(baseUrl, "baseUrl == null");
        List<String> pathSegments = baseUrl.pathSegments();
        if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
            //baseUrl最後必定要接一個 /
            throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
        }
        this.baseUrl = baseUrl;
        return this;
    }

    //把ConverterFactory添加到數據轉化器工廠列表中
    public Builder addConverterFactory(Converter.Factory factory) {
        converterFactories.add(checkNotNull(factory, "factory == null"));
        return this;
    }

    //把CallAdapterFactory添加到網絡請求適配器工廠列表中
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
        callAdapterFactories.add(checkNotNull(factory, "factory == null"));
        return this;
    }
    
   //獲取網絡請求適配器工廠列表
    public List<CallAdapter.Factory> callAdapterFactories() {
      return this.callAdapterFactories;
    }

   //獲取數據轉化器工廠列表
    public List<Converter.Factory> converterFactories() {
      return this.converterFactories;
    }

    //修改validateEagerly標誌位
    public Builder validateEagerly(boolean validateEagerly) {
        this.validateEagerly = validateEagerly;
        return this;
    }

    //...
}

複製代碼

Builder中全部的字段都貼出來了,方法只貼了幾個經常使用的出來,咱們調用Builder的相應方法,就是在爲Builder的相應字段賦值,很簡單,就不介紹了。

其中要注意的是:當咱們添加ConverterFactory或CallAdapterFactory時,它們都是添加到各自的列表中,這說明在Retrofit中Converter和CallAdapter是能夠存在多個的,爲何呢?這是由於Retrofit容許咱們爲Api接口裏面定義的每個方法都定義對應的Converter和CallAdapter,每當咱們調用到Api接口的某個方法時,Retrofit都會遍歷網絡請求適配器工廠列表callAdapterFactories,把方法的返回值returnType和註解信息annotations傳進每一個Factory的get方法中,看某個Factory是否願意處理這個方法,爲這個方法建立對應CallAdapter實例;同理,當Retrofit解析某個Api接口方法的網絡請求數據時,它一樣會遍歷數據轉化器工廠列表converterFactories,把方法的相關信息傳給Factory的responseBodyConverter或requestBodyConverter方法,看某個Factory是否願意處理這個方法,爲這個方法建立對應ResponseBodyBodyConverter或RequestBodyConverter實例,這兩個過程在待會的源碼分析都會體現到。因爲咱們日常開發都只添加了一個CallAdapter和一個Converter,因此Retrofit對Api接口定義的每個方法的adapt和convert都是相同的處理。

配置好Builder後,接下來調用build方法建立Retrofit實例.

三、建立Retrofit實例

//Retrofit.java
public static final class Builder {

    //...

    public Retrofit build() {
        if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
        }

        //配置網絡請求執行器工廠callFactory
        okhttp3.Call.Factory callFactory = this.callFactory;
        //若是沒有指定,使用默認的
        if (callFactory == null) {
            //默認指定爲OkHttpClient, OkHttpClient實現了Call.Factory接口,OkHttpClient和Call都是來自okhttp的
            callFactory = new OkHttpClient();
        }

        //配置線程切換執行器callbackExecutor
        Executor callbackExecutor = this.callbackExecutor;
        //若是沒有指定,使用默認的
        if (callbackExecutor == null) {
            //默認指定爲運行平臺默認的線程切換執行器
            //在Android中,defaultCallbackExecutor方法的返回值就是MainThreadExecutor實例
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        //配置網絡請求適配器工廠列表
        //添加用戶指定的網絡請求適配器工廠列表
        List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
        //添加運行平臺默認的網絡請適配器工廠到列表中
        //在Android中,defaultCallAdapterFactory方法返回值就是ExecutorCallAdapterFactory實例,並把MainThreadExecutor實例傳進方法,因此ExecutorCallAdapterFactory持有MainThreadExecutor實例(回去看構造Builder階段)
        callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

        //配置數據轉化器工廠列表
        List<Converter.Factory> converterFactories =
            new ArrayList<>(1 + this.converterFactories.size());
	   //添加Retrofit默認的數據轉化器工廠BuiltInConverters
        converterFactories.add(new BuiltInConverters());
        //添加用戶指定的數據轉化器工廠列表
        converterFactories.addAll(this.converterFactories);

        //建立一個Retrofit實例返回,並把上面的配置好的字段傳進構造
        //這些字段和Retrofit中相應的字段同名,unmodifiableList就是建立一個不可修改的列表
        return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
                            unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
}
複製代碼

build方法中把沒有在配置Builder階段中賦值的字段指定了默認值,而後把網絡請求Url地址baseUrl、網絡請求執行器工廠callFactory、線程切換執行器callbackExecutor、網絡請求適配器工廠列表callAdapterFactories、數據轉化器工廠列表converterFactories、標誌位validateEagerly這六件套傳進了Retrofit的構造,建立一個Retrofit實例返回。

其中要注意的是,按照添加順序,工廠列表的優先級爲:用戶指定的網絡請適配器工廠列表 > 運行平臺默認的網絡請求適配器工廠;Retrofit默認的數據轉化器工廠 > 用戶指定的數據轉化器工廠列表。在遍歷這些列表時是從前日後遍歷的,越靠前的越先被訪問。

四、小結

通過這3步後,指定了Retrofit的運行平臺,配置好了Retrofit的網絡請求Url地址、網絡請求執行器工廠、線程切換執行器、網絡請求適配器工廠列表、數據轉化器工廠列表等字段,並建立了一個Retrofit實例.

有了Retrofit實例後,就能夠經過Retrofit的create方法建立一個Api接口實例,這也是整個Retrofit最核心的地方.

4、建立Api接口實例

GithubService service = Retrofit.create(GithubService.class);
複製代碼

我先講一下Retrofit的create方法的做用,Retrofit的create方法裏面幹了兩件事,首先它會根據validateEagerly標誌位是否爲true,而從決定是否把Api接口裏定義的全部方法的註解和參數信息提早封裝到ServiceMethod中而後緩存起來,接着就經過Proxy的newProxyInstance方法爲GithubService接口建立一個代理對象返回,這裏就使用到了外觀模式,外觀模式就是定義一個統一接口,外部(用戶)經過該統一的接口對子系統裏的其餘接口進行訪問,這裏的這個統一的接口就是Retrofit.create方法,咱們只須要調用create方法,Retrofit內部就替咱們把這兩件事給作了,不用咱們訪問Retrofit的內部子系統,下降了咱們使用的複雜度。

Retrofit的create方法以下:

//Retrofit.java
//泛型T就是GithubService接口
public <T> T create(final Class<T> service) {
    //傳進來的必須是一個接口,而且這個接口沒有繼承其餘接口,不然拋異常
    Utils.validateServiceInterface(service);
    
    //一、判斷validateEagerly標誌位是否爲true
    if (validateEagerly) {
      //若是爲true,把Api接口裏定義的全部方法的註解和參數信息封裝到ServiceMethod中,提早緩存起來
      eagerlyValidateMethods(service);
    }
    
    //二、經過Proxy的newProxyInstance方法爲GithubService接口建立一個代理對象
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
         		//...
          }
        });
  }

//Retrofit.java
private void eagerlyValidateMethods(Class<?> service) {
    //首先獲取運行平臺,這裏爲Android
    Platform platform = Platform.get();
    //getDeclaredMethods方法會以 Method[] 形式返回接口定義的全部方法的Method對象,因此這裏就是在遍歷接口的全部方法
    for (Method method : service.getDeclaredMethods()) {
      //在Android平臺,isDefaultMethod方法返回false
      if (!platform.isDefaultMethod(method)) {
        //爲每個方法都調用一次loadServiceMethod方法
        //loadServiceMethod方法中就會把方法的註解和參數信息封裝到ServiceMethod中,而後緩存起來
        loadServiceMethod(method);
      }
    }
  }
複製代碼

咱們先看create方法的註釋1,validateEagerly這個標誌位決定是否對serviceMethod進行提早緩存,默認爲false,當爲true時,create方法中就會調用eagerlyValidateMethods方法,裏面會遍歷Api接口的全部方法,爲每個方法都調用一次loadServiceMethod方法(invoke方法中會講到這個方法),loadServiceMethod方法中就會把方法的註解和參數信息封裝到ServiceMethod中,以方法method爲鍵,ServiceMethod爲值,放入一個名叫serviceMethodCache的Map中緩存起來,這個Map定義在Retrofit中,以下:

public final class Retrofit {
  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  //...
}
複製代碼

能夠看到這個Map是一個線程安全的HashMap,它的key = Method,value = ServiceMethod。因此能夠根據須要設置validateEagerly標誌位開啓ServiceMethod的預加載,這樣等到動態執行invoke方法時能夠直接從緩存中獲取ServiceMethod實例。

咱們重點看create方法的註釋2,經過Proxy的newProxyInstance方法爲GithubService接口建立一個代理對象,這裏就使用了動態代理模式,Proxy的newProxyInstance方法會在代碼運行時,根據第一個參數的ClassLoader,生成一個代理Class對象,該代理Class對象實現了傳入的第二個參數對應的Interface列表,在獲取到代理Class對象後,根據第三個參數InvocationHandler引用經過反射建立一個代理對象實例,因此newProxyInstance最終的結果是生成一個代理對象實例,該代理對象會實現給定的接口列表,同時內部持有一個InvocationHandler引用,咱們調用代理對象的方法時,這個方法處理邏輯就會委託給InvocationHandler實例的invoke方法執行

小結

當咱們調用Retrofit的create方法後,它返回了一個代理對象實例,這個代理對象實現了create方法傳進去的接口,接下來當咱們調用Api接口的方法時,就是在調用代理對象的同名方法,這個方法處理邏輯就會委託給InvocationHandler實例的invoke方法執行,使用了動態代理以後的好處就是咱們能夠把發起網絡請求的參數獲取都集中到invoke方法中處理,而不須要爲每個接口定義一個實現類,這樣下降了實現的難度。

接下來咱們開始調用Api接口的方法,它會返回一個網絡請求執行器。

5、調用Api接口實例的方法

Call<ResponseBody> call = service.getUserInfo("rain9155");
複製代碼

根據動態代理的知識,咱們知道,當咱們調用Api接口實例的方法,就是在調用代理對象的方法,這個方法處理邏輯就會委託給InvocationHandler實例的invoke方法執行,也就是說,當咱們在外部調用Api接口的相應方法時,這些方法都會轉到invoke方法執行,例如我調用service.getUserInfo("rain9155")時,這個方法會轉到invoke方法去執行。

因此咱們直接看InvocationHandler的invoke方法邏輯:

//Retrofit.java
public <T> T create(final Class<T> service) {
     //...
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
            
          private final Platform platform = Platform.get();
            
          /** * 當我調用service.getUserInfo("rain9155")時,這個方法會轉到invoke方法去執行。 * @param proxy 代理對象實例 * @param method 被調用的方法,如這裏的getUserInfo方法 * @param args 被調用的方法的參數,如這裏的"rain9155" */
          @Override 
          public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
              
            //若是這個方法是Object類的,調用Object類的方法
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
             
            //在Android平臺,isDefaultMethod方法返回false,不會進入這個分支
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
              
            //走到這裏表示,調用的不是Object類的方法,而是GithubService接口的相應方法
              
            //一、調用loadServiceMethod方法,爲這個方法獲取一個ServiceMethod
            ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
            
            //二、把該方法的ServiceMethod和args傳進okHttpCall,建立一個okHttpCall實例
            //args就是方法的參數
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            
            //三、調用adapt方法,傳入okHttpCall,把okHttpCall適配成另外一個Call
            //裏面其實調用的是CallAdapter的adapt方法
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }
複製代碼

invoke方法中分爲註釋一、二、3,下面分別講解:

註釋一、loadServiceMethod方法

//一、調用loadServiceMethod方法,爲這個方法獲取一個ServiceMethod
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
複製代碼

loadServiceMethod方法以下:

//Retrofit.java 
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //首先從serviceMethodCache根據方法method獲取ServiceMethod
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
     
    //若是獲取獲得就直接返回
    if (result != null) return result;

     //若是獲取不到就爲這個method建立一個ServiceMethod
    //上鎖,因此建立的ServiceMethod是一個單例
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
         //一、爲method建立一個ServiceMethod
        result = new ServiceMethod.Builder<>(this, method).build();
         //而後以方法method爲鍵,ServiceMethod爲值,放入serviceMethodCache緩存起來
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
複製代碼

能夠看到這裏首先從serviceMethodCache根據方法method獲取ServiceMethod,若是獲取不到再爲方法建立一個ServiceMethod,而後以方法method爲鍵,ServiceMethod爲值,放入serviceMethodCache緩存起來,並返回,咱們重點來看註釋1,看這個ServiceMethod是怎樣根據方法的Method對象建立出來的

一、ServiceMethod的建立過程

result = new ServiceMethod.Builder<>(this, method)//1
      .build();//2
複製代碼

ServiceMethod一樣是經過Builder模式建立,因此咱們一樣分註釋的2步去看ServiceMethod的建立.

1.一、構造Builder

因此咱們先看ServiceMethod的Builder的構造,以下:

//ServiceMethod.java
static final class Builder<T, R> {
    final Retrofit retrofit;
    final Method method;
    final Annotation[] methodAnnotations;
    final Annotation[][] parameterAnnotationsArray;
    final Type[] parameterTypes;
	//...

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      //獲取方法裏的全部註解,如@GET、@POST,@PATCH等
      this.methodAnnotations = method.getAnnotations();
      //獲取方法裏的全部參數類型,如int、String等
      this.parameterTypes = method.getGenericParameterTypes();
      //獲取方法裏全部參數的註解,如@Query,@Body、@PartMap等
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
複製代碼

構造中依此獲取方法的註解、參數類型、參數的註解並依此賦值給methodAnnotations、parameterAnnotationsArray、parameterTypes,注意parameterAnnotationsArray是一個二維數組,由於一個參數能夠被多個註解修飾,一個註解能夠修飾多個參數。

1.二、建立ServiceMethod實例

咱們接着看Builder的build方法,以下:

//ServiceMethod.java
static final class Builder<T, R> {
    final Retrofit retrofit;
    final Method method;
    final Annotation[] methodAnnotations;
    final Annotation[][] parameterAnnotationsArray;
    final Type[] parameterTypes;

    Type responseType;
    ParameterHandler<?>[] parameterHandlers;
    Converter<ResponseBody, T> responseConverter;
    CallAdapter<T, R> callAdapter;
    //...

    public ServiceMethod build() {
        
        //一、調用createCallAdapter方法建立網絡請求適配器CallAdapter
        callAdapter = createCallAdapter();

        //經過CallAdapter的responseType方法獲取返回數據的響應body的類型
        //如Call<ResponseBody>,獲取到ResponseBody類型
        responseType = callAdapter.responseType();
        //....省略異常處理

        //二、調用createResponseConverter方法建立網絡返回數據的數據轉化器Converter
        responseConverter = createResponseConverter();

        //遍歷該方法的全部註解
        for (Annotation annotation : methodAnnotations) {
            //三、調用parseMethodAnnotation方法解析註解,如@GET、@POST,@PATCH等
            parseMethodAnnotation(annotation);
        }
        //...省略異常處理

        int parameterCount = parameterAnnotationsArray.length;
        parameterHandlers = new ParameterHandler<?>[parameterCount];
        //爲方法中的每一個參數建立一個ParameterHandler<?>對象並解析每一個參數使用的註解
        for (int p = 0; p < parameterCount; p++) {
            
            //獲取參數類型,如int、String等
            Type parameterType = parameterTypes[p];
             //...省略異常處理

            //獲取修飾參數的註解,如@Query,@Body、@PartMap等
            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
            //...省略異常處理

            //四、調用parseParameter方法解析每一個參數使用的註解,並返回一個parameterHandlers
            parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
        }
        //...省略異常處理

  		//建立ServiceMethod實例,並把Builder實例傳進去
        //ServiceMethod構造裏面會把Builder配置好的字段賦值給ServiceMethod中相應的字段
        return new ServiceMethod<>(this);
    }

複製代碼

build方法裏面分4步,咱們先看註釋一、2,註釋1調用createCallAdapter方法建立網絡請求適配器CallAdapter,並賦值給callAdapter字段,createCallAdapter方法以下:

//ServiceMethod::Builder.java
private CallAdapter<T, R> createCallAdapter() {
    //獲取方法的返回值類型,如Call<ResponseBody>
    Type returnType = method.getGenericReturnType();
    //...省略異常處理
    
    //獲取方法的全部註解,如@GET、@POST,@PATCH等
    Annotation[] annotations = method.getAnnotations();
    try {
        //調用Retrofit的callAdapter方法,返回一個CallAdapter實例
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
    }
    //...省略異常處理
}

//Retrofit.java
 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    //...省略異常處理

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    //遍歷網絡請求適配器工廠callAdapterFactories
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      //把該方法的返回值類型returnType和註解信息annotations傳給CallAdapterFactory的get方法,經過get方法獲取一個CallAdapter實例或null
      //在Retrofit相關類介紹講過,Android平臺的CallAdapterFactor的默認實現是ExecutorCallAdapterFactory,ExecutorCallAdapterFactory的get方法返回一個CallAdapter匿名實現類或null
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
複製代碼

createCallAdapter方法中,獲取到方法的返回值類型(如Call類型)和註解信息後,就調用Retrofit的callAdapter方法,callAdapter方法就調用nextCallAdapter方法,在nextCallAdapter方法中,會遍歷Retrofit的網絡請求適配器工廠callAdapterFactories,把方法的返回值returnType和註解信息annotations傳進每一個Factory的get方法中,看某個Factory是否願意處理這個方法,若是願意,就爲這個方法建立對應CallAdapter實例,在Android平臺中,CallAdapterFactor的默認實現是ExecutorCallAdapterFactory,ExecutorCallAdapterFactory的get方法返回一個CallAdapter匿名實現類。(查看前面講過的Retrofit相關類介紹,裏面有對ExecutorCallAdapterFactory的詳細介紹)

咱們再看build方法裏的註釋2,註釋2調用createResponseConverter方法建立網絡返回數據的數據轉化器Converter,賦值給responseConverter字段,createResponseConverter方法以下:

//ServiceMethod::Builder.java
private Converter<ResponseBody, T> createResponseConverter() {
    //獲取方法的全部註解,如@GET、@POST,@PATCH等
    Annotation[] annotations = method.getAnnotations();
    try {
        //調用Retrofit的responseBodyConverter方法,返回一個Converter實例
        return retrofit.responseBodyConverter(responseType, annotations);
    } 
    //...省略異常處理
}

//Retrofit.java
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
}

public <T> Converter<ResponseBody, T> nextResponseBodyConverter( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    //...省略異常處理

    int start = converterFactories.indexOf(skipPast) + 1;
    //遍歷數據轉化器工廠converterFactories
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        //把該方法的返回值的泛型類型和註解信息annotations傳給ConverterFactory的responseBodyConverter方法,經過responseBodyConverter方法獲取一個處理網絡返回數據的數據轉化器Converter實例或null
        //在Retrofit相關類介紹講過,Retrofit的ConverterFactory的默認實現是BuiltInConverters,BuiltInConverters的responseBodyConverter方法返回一個處理網絡返回數據的數據轉化器Converter實例或null
        Converter<ResponseBody, ?> converter =
            converterFactories.get(i).responseBodyConverter(type, annotations, this);
        if (converter != null) {
            //noinspection unchecked
            return (Converter<ResponseBody, T>) converter;
        }
    }
    //...省略異常處理
}

複製代碼

createResponseConverter方法中的流程和createCallAdapter方法的流程差很少,最終是遍歷Retrofit的數據轉化器工廠converterFactories,把該方法的返回值的泛型類型(如Call,泛型類型就是ResponseBody類型)和註解信息annotations傳給每一個Factory的responseBodyConverter方法中,看某個Factory是否願意處理這個方法,若是願意,就爲這個方法建立對應的網絡返回數據的數據轉化器Converter實例,在Android平臺中ConverterFactory的默認實現是BuiltInConverters (查看前面講過的Retrofit相關類介紹,裏面有對BuiltInConverters的詳細介紹)。有ResponseConverter就有相應的RequestConverter,RequestConverter用來處理網絡請求數據的數據轉化,RequestConverter並不在ServiceMethod的build方法中建立,而是在parseParameter方法中建立。

至於build方法的註釋三、4的parseMethodAnnotation方法和parseParameter方法,限於篇幅,就留給你們本身探索了,我講一下里面的大致邏輯:

  • parseMethodAnnotation方法:該方法裏面首先判斷是哪一種HTTP請求的註解,而後爲不一樣的HTTP請求註解調用parseHttpMethodAndPath方法,該方法裏面會獲取註解中省略域名的Url和把Url裏面須要替換地方用正則找出來放到一個Set中,如:@GET("users/{user}"),省略域名的Url = users/{user},須要替換的地方是{user},把user找出來,最終parseMethodAnnotation方法獲取到的信息是: HTTP請求方式、省略域名的Url和Url中須要替換值的地方
  • parseParameter方法:這個方法是解析方法參數的註解,如@Quary、@Path等,裏面會判斷是哪一種類型的註解,根據不一樣類型的註解,取出註解中的值,建立一個RequestConverter實例,最後把註解的值和RequestConverter實例傳進ParameterHandler構造,爲這個註解建立一個ParameterHandler實例返回,不一樣的註解有不一樣的ParameterHandler類型,如@Quary就有ParameterHandler.Quary,@Path就有ParameterHandler.Path。

都是經過註解解析出註解參數,而後一併封裝到ServiceMethod中去,build方法執行完畢,就建立了一個ServiceMethod實例返回。

咱們來小結一下ServiceMethod的建立過程:

通過這2步後,爲這個方法method建立了一個對應的ServiceMethod實例,這個ServiceMethod封裝了網絡請求所須要的全部參數和持有CallAdapter實例、處理網絡返回數據轉化的Converter實例,同時這個ServiceMethod是一個單例,也就是說Api接口裏的每個方法都分別對應着一個ServiceMethod實例,這個ServiceMethod實例持有着網絡請求所須要的全部參數

咱們繼續回到loadServiceMethod方法中。

二、小結

調用loadServiceMethod方法後,建立了一個ServiceMethod實例並緩存到一個Map中,第二次使用時直接從緩存獲取ServiceMethod實例,沒必要重複建立,提升效率。

咱們回到invoke方法,有了ServiceMethod實例後,就能夠建立一個okHttpCall實例.

註釋二、建立一個okHttpCall實例

//二、把該方法的ServiceMethod和args(args就是方法的參數)傳進okHttpCall,建立一個okHttpCall實例
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
複製代碼

OkHttpCall的構造以下:

final class OkHttpCall<T> implements Call<T> {
    private final ServiceMethod<T, ?> serviceMethod;//封裝了Api接口方法中的註解和參數信息,一個ServiceMethod對應一個Method
    private final @Nullable Object[] args;//表明着Api接口方法中的參數
    private @Nullable okhttp3.Call rawCall;//這是一個來自Okhttp的Call
	//...

  OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
    
 //...
複製代碼

能夠看到Okhttp把剛剛獲得的ServiceMethod實例和接口方法的參數保存起來,OkHttpCall在前面的Retrofit的相關類介紹已經簡單介紹過了,它就是實現了Call的一個類,它裏面的方法大部分邏輯都轉發給Okhttp的Call 。

獲得okHttpCall實例後,經過adapt方法把它適配成另一個Call.

註釋三、把OkHttpCall適配成另外一個Call

//三、調用adapt方法,傳入okHttpCall,把okHttpCall適配成另外一個Call
return serviceMethod.adapt(okHttpCall);
複製代碼

ServiceMethod的adapt方法以下:

//ServiceMethod.java
T adapt(Call<R> call) {
    return callAdapter.adapt(call);
}
複製代碼

adapt方法傳進來的call是OkhttpCall實例,callAdapter就是剛剛用createCallAdapter方法建立的CallAdapter實例,在Android平臺中,這個CallAdapter實例的adapt方法的默認實現就是用ExecutorCallbackCall包裝傳進來的OkHttpCall,並返回ExecutorCallbackCall實例,以下:

final class ExecutorCallAdapterFactory extends CallAdapter.Factory {

    //線程切換執行器, 在建立Retrofit實例時傳進ExecutorCallAdapterFactory中
    //在Android平臺,就是MainThreadExecutor實例
    final Executor callbackExecutor;

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

    //get方法
    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit Retrofit) {
        //...
        final Type responseType = Utils.getCallResponseType(returnType);
        //返回一個CallAdapter匿名類
        return new CallAdapter<Object, Call<?>>() {

            @Override 
            public Type responseType() {
                return responseType;
            }

             //adapt方法
            @Override 
            public Call<Object> adapt(Call<Object> call) {
                //建立了一個ExecutorCallbackCall,並把線程切換執行器實例和OkhttpCall實例傳進構造
                return new ExecutorCallbackCall<>(callbackExecutor, call);
            }
        };
    }

    //網絡請求執行器
    static final class ExecutorCallbackCall<T> implements Call<T> {
		//...
    }
}
複製代碼

因此callAdapter.adapt(call)就是把OkhttpCall 適配成 ExecutorCallbackCall,咱們來看一下ExecutorCallbackCall,它是ExecutorCallAdapterFactory的內部類,以下:

//ExecutorCallAdapterFactory.java
//網絡請求執行器
static final class ExecutorCallbackCall<T> implements Call<T> {
    
    final Executor callbackExecutor;//線程切換執行器實例, 在get方法經過構造傳進
    final Call<T> delegate;//OkhttpCall實例, 在get方法經過構造傳進

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

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

        //ExecutorCallbackCall的enqueue方法委託給OkhttpCall執行
        delegate.enqueue(new Callback<T>() {
            @Override 
            public void onResponse(Call<T> call, final Response<T> response) {
                //當網絡數據返回時,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調
                callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                        if (delegate.isCanceled()) {
                            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                        } else {
                            callback.onResponse(ExecutorCallbackCall.this, response);
                        }
                    }
                });
            }

            @Override 
            public void onFailure(Call<T> call, final Throwable t) {
                //當網絡數據返回時,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調
                callbackExecutor.execute(new Runnable() {
                    @Override public void run() {
                        callback.onFailure(ExecutorCallbackCall.this, t);
                    }
                });
                
            }
        });
    }

    @Override 
    public Response<T> execute() throws IOException {
        //ExecutorCallbackCall的execute方法委託給OkhttpCall執行
        return delegate.execute();
    }

    //...

}
複製代碼

能夠看到,ExecutorCallbackCall和OkhttpCall同樣都實現了Call接口中的方法,而且ExecutorCallbackCall中持有OkhttpCall的實例,它的enqueue方法和execute方法都委託給OkhttpCall的enqueue方法和execute方法執行,當網絡數據返回時,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調,這裏採用了裝飾者模式,採用裝飾者模式的好處就是不用經過繼承就能夠擴展一個對象的功能,動態的給一個對象添加一些額外的操做,這裏額外的操做就是經過線程切換執行器切換回主線程後再執行callback回調,由於OkHttpCall的enqueue方法是進行網絡的異步請求,當異步請求結果返回時,回調是在子線程中,須要經過線程切換執行器轉換到主線程中再進行callback回調。

最終,ServiceMethod的adapt方法把OkhttpCall 適配成不一樣平臺的網絡請求執行器,並返回,在Android平臺中,OkhttpCall 適配成了 ExecutorCallbackCall實例。

四、小結

當咱們調用Api接口實例中的方法時,這些方法的處理邏輯都會轉發給invoke方法,在invoke方法中,會爲每個方法建立一個ServiceMethod,這個ServiceMethod封裝了網絡請求所須要的全部參數和持有CallAdapter實例、處理網絡返回數據轉化的Converter實例,接着就會把這個ServiceMethod實例和接口方法的參數傳進OkhttpCall的構造中,建立一個OkhttpCall實例,接着把這個OkhttpCall實例傳給ServiceMethod的adapt方法,ServiceMethod的adapt方法就會調用CallAdapter實例的adapt方法,把OkhttpCall適配成不一樣平臺的網絡請求執行器,因此若是你添加了其餘平臺的CallAdapterFactory,你就能夠獲得不一樣平臺下的網絡請求執行器,在Android平臺中,CallAdapter實例的adapt方法會把OkhttpCall適配成ExecutorCallbackCall,這個ExecutorCallbackCall持有OkhttpCall實例和線程切換器MainThreadExecutor實例,當咱們發起網絡請求時,ExecutorCallbackCall就會委託OkhttpCall發起網絡請求,當網絡請求數據返回時,ExecutorCallbackCall就會經過MainThreadExecutor把線程切換主線程執行回調。

獲得網絡請求執行器以後,就能夠發起,網絡請求了.

6、發起網絡請求(以異步爲例)

不一樣平臺下的網絡請求執行器不一樣,在Android平臺,調用Api接口實例的方法後返回的是ExecutorCallbackCall,有了ExecutorCallbackCall後,咱們就能夠發起同步或異步請求,同步和異步請求的流程類型,惟一不一樣的是異步請求須要把結果經過Callback回調給上層,而同步請求則是直接return結果給上層。

下面以異步請求爲例:

//用戶發起異步請求 
call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response){
            	//經過Response獲取網絡請求返回結果
                ResponseBody body = response.body();
                try {
                    Log.d(TAG, "請求結果:" +  body.string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

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

            }
        });
複製代碼

調用的是ExecutorCallbackCall的enqueue方法,以下:

//ExecutorCallAdapterFactory::ExecutorCallbackCall.java
public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");

    //ExecutorCallbackCall的enqueue方法委託給OkhttpCall執行
    delegate.enqueue(new Callback<T>() {
        @Override 
        public void onResponse(Call<T> call, final Response<T> response) {
            //當網絡數據返回時,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調
            callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                    if (delegate.isCanceled()) {
                        callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                        callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                }
            });
        }

        @Override 
        public void onFailure(Call<T> call, final Throwable t) {
            //當網絡數據返回時,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調
            callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                    callback.onFailure(ExecutorCallbackCall.this, t);
                }
            });

        }
    });
複製代碼

調用的是OkhttpCall的enqueue方法,以下:

//OkhttpCall.java
private @Nullable okhttp3.Call rawCall;//這是一個來自Okhttp的Call

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

    //來自Okhttp的Call
    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      //一、獲取Okhttp的Call實例
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //第一次發起網絡請求,建立Okhttp的Call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
       //經過callback把錯誤回調出去
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }

    //二、調用Okhttp的Call的enqueue方法發起異步請求
    //傳入的是Okhttp的Callback
    call.enqueue(new okhttp3.Callback() {
        
       //Okhttp的結果回調
      @Override 
       public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
          //三、調用parseResponse方法把Okhttp的Response解析成Retrofit的Response
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }

        try {
            //經過callback把結果回調出去
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

     //Okhttp的錯誤回調
      @Override
      public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }

      private void callFailure(Throwable e) {
        try {
           //經過callback把錯誤回調出去
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }
複製代碼

OkhttpCall的enqueue方法大致分爲3步:

一、獲取Okhttp的Call實例,賦值給臨時變量call:

​ 1.一、若是是第一次發起網絡請求,就調用createRawCall方法就建立來自Okhttp的Call,賦值給臨時變量call和成員變量rawCall;

​ 1.二、若是不是第一次發起網絡請求,就把上次的rawCall實例賦值給臨時變量call.

二、調用Okhttp的Call的enqueue方法發起異步請求(更多細節請查看上一篇文章okhttp3源碼分析之請求流程);

三、當網絡請求結果正確返回時,用parseResponse方法把Okhttp的Response解析成Retrofit的Response.

因此咱們來看一下兩個關鍵的辦法,createRawCall方法和parseResponse方法:

一、建立Okhttp的Call

createRawCall方法以下:

//OkhttpCall.java
private okhttp3.Call createRawCall() throws IOException {
    //調用serviceMethod的toCall方法,並把args即接口方法參數傳了進去
    //args在建立OkhttpCall實例時經過構造傳進來的
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
複製代碼

createRawCall方法調用ServiceMethod的toCall方法,以下:

//ServiceMethod.java
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
    
    //一、建立一個用於構造Request的Builder,並把ServiceMethod中封裝的參數傳進去
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
                                                       contentType, hasBody, isFormEncoded, isMultipart);
    
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
      //...省略異常處理

    //二、遍歷每一個方法參數的ParameterHandler
    for (int p = 0; p < argumentCount; p++) {
        //調用ParameterHandler的apply方法,把ParameterHandler中的參數apply到requestBuilder中
        handlers[p].apply(requestBuilder, args[p]);
    }

    //三、requestBuilder.build方法建立一個Request實例傳進newCall方法,這個Request是來自Okhttp的
    //而後調用callFactory的newCall方法建立一個Call
    //這個callFactory就是OkHttpClient時,在建立Retorfit時配置
    //因此這裏返回的是來自Okhttp的Call
    return callFactory.newCall(requestBuilder.build());
}
複製代碼

首先建立一個用於構造Request的requestBuilder,並把ServiceMethod中封裝的參數傳進去,而後遍歷每一個方法參數的ParameterHandler,經過apply方法取出ParameterHandler中的參數放入requestBuilder中,ParameterHandler前面講過,它裏面保存了每一個方法參數的註解的值和處理這些值的Converter實例,構造Request的參數都有了,接着就經過requestBuilder.build方法建立一個Okhttp的Request實例並傳進newCall方法,最後經過OkHttpClient的newCall方法建立一個Okhttp的Call實例返回。

最終createRawCall方法返回一個來自Okhttp的Call實例。

二、解析返回結果

parseResponse方法以下:

//ServiceMethod.java
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    //取出Okhttp的Response的body
    ResponseBody rawBody = rawResponse.body();

    //...省略的是一些狀態碼處理

    //用ExceptionCatchingRequestBody包裝一下rawBody
    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
        //調用ServiceMethod的toResponse方法把原始的body轉化成咱們須要的數據類型
        T body = serviceMethod.toResponse(catchingBody);
        //
        return Response.success(body, rawResponse);
    } 
    //...省略異常處理
}
複製代碼

首先把Okhttp的Response的body取處理,而後用ExceptionCatchingRequestBody包裝一下,這個ExceptionCatchingRequestBody是繼承自Okhttp的ResponseBody,接着把這個ResponseBody傳進ServiceMethod的toResponse方法,裏面會使用ServiceMethod保存的處理網絡返回數據的Converter實例來把這個ResponseBody轉化成咱們須要的數據類型,ServiceMethod的toResponse方法以下:

//ServiceMethod.java
R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }
複製代碼

這個responseConverter就是在建立ServiceMethod時用createResponseConverter方法建立的Converter實例,把body轉化成R類型,不一樣的數據轉化有不一樣的實現,在Retrofit的默認實現中,它就是直接返回ResponseBody。

咱們再回到parseResponse方法,調用完ServiceMethod的toResponse方法,獲得了轉化後的body,最後調用了Response的success方法,把Okhttp的Response和轉化後的body傳了進去,最終返回一個Retrofit的Response。

三、小結

以異步爲例,Retrofit經過ExecutorCallbackCall的enqueue方法發起網絡請求,最終會經過OkhttpCall的enqueue方法來發起網絡請求,OkhttpCall的enqueue方法中,首先會調用建立一個來自Okhttp的Call實例,而後經過這個Okhttp的Call實例的enqueue方法來發起異步請求,當網絡結果Okhttp的Response返回時,調用parseResponse方法解析Response,parseResponse方法裏面還會調用ServiceMethod的toResponse方法經過Converter實例的convert方法把ResponseBody轉化成咱們想要的數據,不一樣的數據轉化有不一樣的實現,在Retrofit的默認實現中,它就是直接返回Okhttp的ResponseBody,最後把這個轉化後的body和原始的Okhttp的Response一併封裝成Retrofit的Response返回,最後把parseResponse方法返回的Response經過callback回調出去,這時ExecutorCallbackCall收到回調,經過線程切換執行器callbackExecutor,切換到主線程執行callback回調,一次異步請求就完成了,同步請求也是大同小異,只是少了個回調,就留給你們本身分析了。

總結

可以閱讀到這裏,說明你對Retrofit的理解又更上一層樓了,其實從總體去看Retrofit,它的流程並不複雜,它的使用也很是的簡單,這得益於它優秀的架構,和運用得當的設計模式,其中最核心的當屬動態代理模式,經過一個代理類InvocationHandler代理N多個接口,它把每個方法的處理邏輯都集中到了invoke方法中,這樣就能在同一處地方處理全部方法的註解解析,還有它那面向接口的設計,使得各個子模塊之間下降耦合,讓咱們以最小的代價替換成咱們須要的實現,Retrofit的總體流程圖以下:

一句話歸納Retrofit:它是一個經過動態代理把Api接口方法的註解解析成網絡請求所需參數,最後經過Okhttp執行網絡請求的封裝庫。

以上就是本文的全部內容,若有錯誤,歡迎指出。

參考資料:

Retrofit解析之面向接口編程

相關文章
相關標籤/搜索