Android - 剖析Retrofit(2)- 动态代理

137 阅读2分钟

源码分析基于 2.7.0

juejin.cn/post/709462… 主要分析了Retrofit重要的属性以及如何构建。

Retrofit的动态代理

关于什么是动态代理,可以看下我之前写的juejin.cn/post/709461…

在构建完Retrofit对象以后就要生成代理对象,以下是生成代理对象比较常见的代码;

public interface ApiService {
    @GET("productList/{userId}")
    Call<Bean> getProductList(@Path("userId") String userId);
}
public class RetrofitRequest {
    private ApiService mApi;
    public void init(Context context) {
        ......
        mApi = retrofit.create(ApiService.class);//1
    }
    
//Retrofit类中    
public <T> T create(final Class<T> service) {
     ......
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
        ......
          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            if (method.getDeclaringClass() == Object.class) {//如果方法是Object定义的方法,则忽略
              return method.invoke(this, args);
            }
              ......
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);//2
          }
        });
  }
  • 注释1:利用Retrofit.create生成动态代理对象,ApiService.class是被代理者;
  • 注释2:loadServiceMethod获取对应的方法发起网络请求,这里的invoke不是反射;
我们以发送getProductList请求来分析源码

利用生成的代理对象mApi执行getProductList方法,执行到Retrofit.loadServiceMethod

 ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);//1
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {//2
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
  • 注释1:从缓存中查找ServiceMethod;
  • 注释2:因为是第一次调用getProductList方法,所以需要构建ServiceMethod.parseAnnotations
 static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//1 最后调用下面Builder模式来构建

    Type returnType = method.getGenericReturnType();
    ......
    if (returnType == void.class) {//方法定义必须得有返回值
      throw methodError(method, "Service methods cannot return void.");
    }
    ·······
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//2 最后调用下面的静态方法parseAnnotations
  }

//RequestFactory类中
Builder(Retrofit retrofit, Method method) {//3
      this.retrofit = retrofit;//retrofit对象
      this.method = method;//调用的Method,getProductList
      this.methodAnnotations = method.getAnnotations();//方法注解,例如@GET("productList/{userId}")
      this.parameterTypes = method.getGenericParameterTypes();//方法参数类型,例如String id
      this.parameterAnnotationsArray = method.getParameterAnnotations();//参数注解,例如@Query("id")
    }

    RequestFactory build() {
     ......
      return new RequestFactory(this);
    }
 
//HttpServiceMethod类中
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(//4
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ......
    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;//OKHttpClient
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    }  
 ......
  }

  • 注释1:调用注释3 构建者模式构建RequestFactory,这是对请求的封装,例如获取方法注解(GET、POST等)、参数注解、请求参数类型,method对getProductList方法的封装,包括方法名;
  • 注释2:调用注释4 静态方法构建CallAdapted(HttpServiceMethod内部类),它的父类是ServiceMethod;CallAdapted封装了requestFactory(参数、注解相关)、callFactory(OKHttpClient相关)、responseConverter(返回结果解析相关)、callAdapter(返回值相关);
  • 至此,我们得到了一个CallAdapted,它对某个网络请求的封装;loadServiceMethod(method).invoke(args != null ? args : emptyArgs)是发起网络请求,留到下次再分析哈
loadServiceMethod大体流程

1.png

总结
  • Retrofit运用动态代理,对Java方法进行解析,封装成一个对象CallAdapted方便后续执行网络请求;
  • CallAdapted(HttpServiceMethod内部类),它的父类是ServiceMethod;CallAdapted封装了requestFactory(参数、注解相关)、callFactory(OKHttpClient相关)、responseConverter(返回结果解析相关)、callAdapter(返回值相关);

以上分析有不对的地方,请指出,互相学习,谢谢哦!