美文网首页Programmer
Retrofit源码阅读

Retrofit源码阅读

作者: 崔鹏宇 | 来源:发表于2021-04-16 14:11 被阅读0次

    前言

    • 为什么要看Retrofit源码?

      • 因为目前项目使用的Retrofit网络请求。想去详细了解下。
    • 这次阅读重点关注的点通过Create方法追踪工作流程

      • 如何进行线程切换
      • 用到反射如何去优化性能的
      • 怎么解析参数和注解的
      • 它针对Kotlin做哪些处理
    • 本次阅读源码版本依赖

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

    • 来张图

      retrofit.png

    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的


          retrofit-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

    相关文章

      网友评论

        本文标题:Retrofit源码阅读

        本文链接:https://www.haomeiwen.com/subject/ajdelltx.html