Retrofit源碼閱讀

前言

  • 爲什麼要看Retrofit源碼?

    • 因爲目前項目使用的Retrofit網絡請求。想去詳細瞭解下。
  • 這次閱讀重點關注的點通過Create方法追蹤工作流程

    • 如何進行線程切換
    • 用到反射如何去優化性能的
    • 怎麼解析參數和註解的
    • 它針對Kotlin做哪些處理
  • 本次閱讀源碼版本依賴

    • implementation 'com.squareup.retrofit2:retrofit:2.9.0'
      implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
      
  • 分析不對的地方請指出。。。

  • 來張圖

Retrofit 基本使用

  • 創建接口

    用於存放請求地址參數信息

    interface ApiService {
        @GET("users/{user}/repos")
        fun listRepos(@Path("user") user: String?): Call<ResponseBody>?
    }
    
  • 發起請求與Retrofit配置

    class MainActivity : AppCompatActivity(), View.OnClickListener {
        private var mApiService: ApiService? = null
    
        private var mBinding: ActivityMainBinding? = null
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            mBinding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(mBinding?.root)
            mBinding?.tvData?.setOnClickListener(this)
            //retrofit配置
            val retrofit = Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .build()
           //接口實例
            mApiService = retrofit.create(ApiService::class.java)
        }
    
        override fun onClick(v: View?) {
            requestData()
        }
       
        //發起請求
        private fun requestData() {
            mApiService?.listRepos("brycecui")?.enqueue(object : Callback<ResponseBody> {
                override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                    Log.e("MainActivity", "onResponse:${response.body().toString()}")
                }
    
                override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
                    Log.e("MainActivity", "onFailure${t.localizedMessage}")
                }
    
            })
        }
    
    }
    

問題分析

Create方法源碼

public <T> T create(final Class<T> service) {
  validateServiceInterface(service);
  return (T)
      Proxy.newProxyInstance(
          service.getClassLoader(),
          new Class<?>[] {service},
          new InvocationHandler() {
            //註釋①
            private final Platform platform = Platform.get();
            private final Object[] emptyArgs = new Object[0];

            @Override
            public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                throws Throwable {
              // If the method is a method from Object then defer to normal invocation.
              if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
              }
              args = args != null ? args : emptyArgs;
              //註釋②
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}
  • 註釋①。獲取對應平臺

    • private static final Platform PLATFORM = findPlatform();
      
      static Platform get() {
        return PLATFORM;
      }
      
      //得到Android平臺
      private static Platform findPlatform() {
        return "Dalvik".equals(System.getProperty("java.vm.name"))
            ? new Android() //
            : new Platform(true);
      }
      //省略部分代碼
        static final class Android extends Platform {
          Android() {
            super(Build.VERSION.SDK_INT >= 24);
          }
          @Override
          public Executor defaultCallbackExecutor() {
            return new MainThreadExecutor();
          }
      //省略部分代碼
          
          static final class MainThreadExecutor implements Executor {
            private final Handler handler = new Handler(Looper.getMainLooper());
      
            @Override
            public void execute(Runnable r) {
              //切換線程
              handler.post(r);
            }
          }
        }
      

      會得到一個Android平臺。

  • 註釋②。會返回false走到loadServiceMethod方法

    • 看下loadServiceMethod源碼

      private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
      ServiceMethod<?> loadServiceMethod(Method method) {
        ServiceMethod<?> result = serviceMethodCache.get(method);
        if (result != null) return result;
      
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            //解析數據得到ServiceMethod
            result = ServiceMethod.parseAnnotations(this, method);
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
      

      如果(線程安全的ConcurrentHashMap)緩存中有直接返回。沒有解析並儲存之後返回ServiceMethod

    • 看下他解析數據的過程源碼

      abstract class ServiceMethod<T> {
        static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
          
          RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
      
          //省略部分代碼
          
          return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
        }
      
        abstract @Nullable T invoke(Object[] args);
      }
      

      ServiceMethod是一個抽象類。

      • RequestFactory的parseAnnotations源碼

        //建造者模式
        static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
          return new Builder(retrofit, method).build();
        }
        
        
      • RequestFactory構造方法

        RequestFactory(Builder builder) {
          method = builder.method;
          baseUrl = builder.retrofit.baseUrl;
          httpMethod = builder.httpMethod;
          relativeUrl = builder.relativeUrl;
          headers = builder.headers;
          contentType = builder.contentType;
          hasBody = builder.hasBody;
          isFormEncoded = builder.isFormEncoded;
          isMultipart = builder.isMultipart;
          parameterHandlers = builder.parameterHandlers;
          isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
        }
        
      • RequestFactory.Builder和它的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);
          }
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
            parameterHandlers[p] =
                parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
          }
          //省略部分空檢查代碼
          return new RequestFactory(this);
        }
        
      • 我看看下返回的RequestFactory都有啥。看下圖是使用上面簡單使用的例子debug的


        baseUrl:就是retrofit傳過來的baseUrl

        httpMethod:我們用的GET註解。(用的POST就是POST)我們可以看下如何進行解析的

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

        根據使用instanceof 判斷是那種註解進行對應的方法解析。也就是parseHttpMethodAndPath方法。

        private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
          //省略httpMethod空異常檢查
          this.httpMethod = httpMethod;
          this.hasBody = hasBody;
          if (value.isEmpty()) {
            return;
          }
          // Get the relative URL path and existing query string, if present.
          int question = value.indexOf('?');
          if (question != -1 && question < value.length() - 1) {
            // Ensure the query string does not have any named parameters.
            String queryParams = value.substring(question + 1);
            Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
            if (queryParamMatcher.find()) {
              throw methodError(
                  method,
                  "URL query string \"%s\" must not have replace block. "
                      + "For dynamic query parameters use @Query.",
                  queryParams);
            }
          }
        
          this.relativeUrl = value;
          this.relativeUrlParamNames = parsePathParameters(value);
        }
        /***********************************手動分割線******************************************/
        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;
            }
        

        parseHttpMethodAndPath 的value是 請求方法註解裏面的值。對應示例中是users/{user}/repos。由於沒有所以不會走if語句。

        relativeUrl也就等於users/{user}/repos

  • 在看下ServiceMethod返回的HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法

    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
        Retrofit retrofit, Method method, RequestFactory requestFactory) {
      boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
      boolean continuationWantsResponse = false;
      boolean continuationBodyNullable = false;
      Annotation[] annotations = method.getAnnotations();
      Type adapterType;
      if (isKotlinSuspendFunction) {
        Type[] parameterTypes = method.getGenericParameterTypes();
        Type responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
        if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
          // Unwrap the actual body type from Response<T>.
          responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
          continuationWantsResponse = true;
        } else {
          // TODO figure out if type is nullable or not
          // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
          // Find the entry for method
          // Determine if return type is nullable or not
        }
        adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
        annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
      } else {
        adapterType = method.getGenericReturnType();
      }
    
      CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
      Type responseType = callAdapter.responseType();
      
      Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
    
      okhttp3.Call.Factory callFactory = retrofit.callFactory;
      if (!isKotlinSuspendFunction) {
        return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
      } else if (continuationWantsResponse) {
        //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
        return (HttpServiceMethod<ResponseT, ReturnT>)
            new SuspendForResponse<>(
                requestFactory,
                callFactory,
                responseConverter,
                (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
      } else {
        //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
        return (HttpServiceMethod<ResponseT, ReturnT>)
            new SuspendForBody<>(
                requestFactory,
                callFactory,
                responseConverter,
                (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
                continuationBodyNullable);
      }
    }
    

    isKotlinSuspendFunction用來判斷是否使用kotlin協程請求。

    true代表使用掛起函數。那麼會創建SuspendForResponse和SuspendForBody。分別是返回值爲Ressponse<T>和ResponseBody。

    分別在內部調用了擴展函數。使用協程切換線程

    //返回值爲Ressponse使用
    suspend fun <T> Call<T>.awaitResponse(): Response<T> {
      return suspendCancellableCoroutine { continuation ->
        continuation.invokeOnCancellation {
          cancel()
        }
        enqueue(object : Callback<T> {
          override fun onResponse(call: Call<T>, response: Response<T>) {
            continuation.resume(response)
          }
    
          override fun onFailure(call: Call<T>, t: Throwable) {
            continuation.resumeWithException(t)
          }
        })
      }
    }
    //返回值爲ResponseBody使用。成功直接返回ResponseBody
    suspend fun <T : Any> Call<T>.await(): T {
      return suspendCancellableCoroutine { continuation ->
        continuation.invokeOnCancellation {
          cancel()
        }
        enqueue(object : Callback<T> {
          override fun onResponse(call: Call<T>, response: Response<T>) {
            if (response.isSuccessful) {
              val body = response.body()
              if (body == null) {
                val invocation = call.request().tag(Invocation::class.java)!!
                val method = invocation.method()
                val e = KotlinNullPointerException("Response from " +
                    method.declaringClass.name +
                    '.' +
                    method.name +
                    " was null but response body type was declared as non-null")
                continuation.resumeWithException(e)
              } else {
                continuation.resume(body)
              }
            } else {
              continuation.resumeWithException(HttpException(response))
            }
          }
    
          override fun onFailure(call: Call<T>, t: Throwable) {
            continuation.resumeWithException(t)
          }
        })
      }
    }
    

    最終會返回一個CallAdapted<>,而CallAdapted<>是繼承的HttpServiceMethod。

    static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
      private final CallAdapter<ResponseT, ReturnT> callAdapter;
      CallAdapted(
          RequestFactory requestFactory,
          okhttp3.Call.Factory callFactory,
          Converter<ResponseBody, ResponseT> responseConverter,
          CallAdapter<ResponseT, ReturnT> callAdapter) {
        super(requestFactory, callFactory, responseConverter);
        this.callAdapter = callAdapter;
      }
    
      @Override
      protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
      }
    }
    
                            而loadServiceMethod(method)的invoke(args)方法。會調用CallAdapted的adapte方法。而這個CallAdapted是由HttpServiceMethod的 createCallAdapter方法創建的。也就是retrofit的addCallAdapterFactory方法添加的。示例中我們沒有添加所以走得是默認的CallAdapted。在retrofit的Builder類中可以找到
    
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//這添加一個平臺默認的CallAdapter並且傳一個線程池callbackExecutor
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//可以看到defaultCallbackExecutor也是由平臺默認的額
 Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

我們看下平臺platform這倆個默認方法。

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
    @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  return hasJava8Types
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
}

繼續看DefaultCallAdapterFactory

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
//省略空檢查
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

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

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

      @Override
      public Call<Object> adapt(Call<Object> call) {
        //當時kotlin協程請求時返回okhttpcall 否則返回ExecutorCallbackCall
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

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

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

      //(OkHttp封裝類)OkHttpCall的enqueue方法進行請求
      delegate.enqueue(
          new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {
              //線程切換
              callbackExecutor.execute(
                  () -> {
                    if (delegate.isCanceled()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                    } else {
                      callback.onResponse(ExecutorCallbackCall.this, response);
                    }
                  });
            }

            @Override
            public void onFailure(Call<T> call, final Throwable t) {
              callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
            }
          });
    }

    @Override
    public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override
    public Response<T> execute() throws IOException {
      return delegate.execute();
    }

    @Override
    public void cancel() {
      delegate.cancel();
    }

    @Override
    public boolean isCanceled() {
      return delegate.isCanceled();
    }

    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override
    public Call<T> clone() {
      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }

    @Override
    public Request request() {
      return delegate.request();
    }

    @Override
    public Timeout timeout() {
      return delegate.timeout();
    }
  }
}

也就是說我們示例中的mApiService?.listRepos("brycecui")?.enqueue()最終到了這裏。delegate他是 Call<T>接口。它的實現類是OkHttpCall。怎麼知道不是別的實現類。上面我們通過代碼追蹤知道了loadserviceMethod.invoke.實際是調用了 抽象類ServiceMethod的實現類HttpServiceMethod的invoke方法。也就是下面這個方法。下面調用了adapt方法並把OkHttpCall傳了過去。最終也就是通過DefaultCallAdapterFactory的get方法的adapt創建一個ExecutorCallbackCall傳遞的。

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

看下 callbackExecutor.execute。線程切換關鍵所在。

static final class MainThreadExecutor implements Executor {
  private final Handler handler = new Handler(Looper.getMainLooper());
  @Override
  public void execute(Runnable r) {
    handler.post(r);
  }
}

也就是使用handler.post(r);切換到主線程。

總結

  • 如何切換線程

    • kotlin 使用協程
    • 默認使用handler
  • 用到反射如何優化性能的

    • 使用map緩存避免多次反射浪費性能
  • 如何解析參數註解

    • 使用反射解析、正則匹配
  • 針對kotlin做了哪些處理

    • 判斷是否使用kotlin並且針對返回值是否只需要body
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章