Retrofit 2.5.0 源碼分析

首先要知道Retrofit 只是一個封裝的網絡框架,而非網絡請求自己。java

一個簡單的網絡請求示例

retrofit = new Retrofit.Builder()
                    .baseUrl("https://www.wanandroid.com")
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(httpClient.build())
                    .build();
  ApiStores apiStore =retrofit.create(ApiStores.class);
  Call<HomeDetailJson> call = apiStore.getHomeDetail();
  call.enqueue(new Callback<HomeDetailJson>() {
            @Override
            public void onResponse(Call<HomeDetailJson> call, Response<HomeDetailJson> response) {
                Log.d(TAG, "onResponse-->");
                HomeDetailJson json = response.body();
            }

            @Override
            public void onFailure(Call<HomeDetailJson> call, Throwable t) {
                Log.d(TAG, "onFailure-->" + t.toString());
            }
        });
複製代碼

其中ApiStore.class 是網絡請求api,最終會經過層層解析,對應到ServiceManager類中android

public interface ApiStores {
    @GET("/article/list/0/json")
    Call<HomeDetailJson> getHomeDetail();
}

複製代碼

在這個Retrofit 框架中最重要也是必需要理解的設計模式是動態代理模式,若是有同窗不理解的,先去看一下動態代理設計模式。json

總而言之,就是apiStore.getHomeDetail()轉爲生成的動態代理類中去處理了。設計模式

如今咱們開始扒源碼

  • new Retrofit.Builder()
public Builder() {
      this(Platform.get());
    }
 Builder(Platform platform) {
      this.platform = platform;
    }
複製代碼

在new Builder的過程當中,主要是找到了對應的platform變量api

private static final Platform PLATFORM = findPlatform();
 static Platform get() {//單利模式
    return PLATFORM;
  }
  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  } 
複製代碼

其實就是不一樣的平臺返回不一樣的類,在Android 平臺下對應的Platform 就是Android()緩存

  • baseUrl("www.wanandroid.com") 這段就不帶着去看源碼了,其實就是構造出okHttp 中使用的HttpUrlbash

  • addConverterFactory(GsonConverterFactory.create()) 數據解析使用網絡

public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
//一個判空檢查

複製代碼

GsonConverterFactory.create(),一個使用Gson 作數據解析的類框架

public static GsonConverterFactory create() {
    return create(new Gson());
  }
  public static GsonConverterFactory create(Gson gson) {
    return new GsonConverterFactory(gson);
  }
  private final Gson gson;
  private GsonConverterFactory(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    this.gson = gson;
  }
複製代碼
  • client(httpClient.build())
public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }
//指定了網絡請求框架使用okHttp,其實Android 平臺默認也是使用OKHttp 可是由於我要作網絡log 日誌打印,因此本身設置了一下
複製代碼
  • build() 這個方法主要是完成變量的賦值操做,咱們挑一些重要的變量來看一下
public Retrofit build() {
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //設置網絡請求框架,默認是OkHttp

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
     //回調執行器: MainThreadExecutor
     
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      //網絡請求適配器,轉換成不一樣平臺試用的網絡請求執行器:ExecutorCallAdapterFactory

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
    //數據解析適配器

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
複製代碼
  • 重點來了,最重要的設計模式:代理模式。感受這個是Retrofit 的靈魂,哇哈哈 retrofit.create(ApiStores.class);經過調用生成代理類,咱們解析一下生成代理類的過程。
public <T> T create(final Class<T> service) {
    //咱們直接看return方法,調用了Proxy.newProxyInstance()這個方法就是用來動態生成代理類,
    //此處推薦一篇動態代理的文章 https://blog.csdn.net/lovejj1994/article/details/78080124,相信你們看完這篇文章就知道newProxyInstance 到底作了什麼,以及生成了一個什麼樣的動態代理類。
    //最終的結果:Interface中對動態method 的調用都會走下面的invoke 方法。
    //那麼在代理的解析過程當中都發生了什麼呢?
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {//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);
          }
        });
  }
複製代碼

loadServiceMethod()有一個很重要的做用就是生成網絡請求對象 ServiceManageride

//作了優化,會根據Method 作緩存
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  
  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    //從緩存中獲取對應的ServiceManager 對象
    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;
  }
複製代碼

從上面畫的這個不規範的時序圖能夠看出,最終生成了HttpServiceMethod 這個類, 那invoke()方法也就調到對應的類中來看作了什麼事情

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

callAdapter 從上面的時序圖中,能夠得出對應的實際類是ExecutorCallAdapterFactory 中經過get()方法new CallAdapter,那adapt()方法的調用也就是返回了ExecutorCallBackCall

  • call.enqueue 也就是ExecutorCallBackCall.enqueue
@Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
    
    //從上面的源碼分析可得出delegate 對應的是OkHttpCall,因此下面的enqueue轉向了OkHttp網絡請求框架的邏輯,此處再也不分析
      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation. callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled")); } else { callback.onResponse(ExecutorCallbackCall.this, response); } } }); } @Override public void onFailure(Call<T> call, final Throwable t) { callbackExecutor.execute(new Runnable() { @Override public void run() { callback.onFailure(ExecutorCallbackCall.this, t); } }); } }); } 複製代碼
相關文章
相關標籤/搜索