Retrofit原理篇 (一)动态代理、适配器CallAdaper、数据转换器Convert、网络请求Call原理分析

1,963 阅读7分钟

本文将以retrofit使用流程的角度来讲解retrofit的设计原理。(建议先看目录,再阅读文章)

先讲一下"上古时代"retrofit的用法。

后端文档:

  1. 接口 www.wanandroid.com/hotkey/json
  2. 请求方式 GET
  3. 响应示例
{
	"data": [{
		"id": 8,
		"link": "",
		"name": "逆向 加固",
		"order": 8,
		"visible": 1
	}],
	"errorCode": 0,
	"errorMsg": ""
}

客户端开发:

一,基本使用流程

1,定义响应数据bean

//对应响应的数据结构
class ApiResult<T> {
    var errorCode: String? = null
    var errorMsg: String? = null
    var data: T? = null
}

//对应data的数据结构
data class Info(
    val id: Int? = 0,
    val name: String? = "",
    val link: String? = "",
    val order: Int? = 0,
    val visible: Int? = 0
)

2,定义描述网络请求的接口

interface HotKeyApiInterface {

    @GET("/hotkey/json")
    fun getDataWithCall(): Call<ApiResult<List<Info>>>
    
}

3,创建Retrofit实例

val retrofit = Retrofit.Builder()
    .baseUrl("https://www.wanandroid.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

4,创建步骤2中描述网络请求接口的代理

val apiProxy = retrofit.create(HotKeyApiInterface::class.java)

5,创建网络请求Call

val call: Call  = apiProxy.getDataWithCall()

6,进行同步请求或异步请求

//进行同步请求
val response = call.execute()
val apiResult = response.body() //得到我们定义的ApiResult


//进行异步请求
call.enqueue(object : Callback<ApiResult<List<Info>>> {
    override fun onResponse(
        call: Call<ApiResult<List<Info>>>,
        response: Response<ApiResult<List<Info>>>
    ) {
        val apiResult = response.body() //得到我们定义的ApiResult
    }

    override fun onFailure(call: Call<ApiResult<List<Info>>>, t: Throwable) {
        TODO("Not yet implemented")
    }
})

二,retrofit中的注解类型

从上面步骤2定义描述网络请求接口的代码为:

interface HotKeyApiInterface {

    @GET("/hotkey/json")
    fun getDataWithCall(): Call<ApiResult<List<Info>>>
    
}

这里用@GET注解描述当前请求的请求方式为GET请求,请求路径为"hotkey/json"。

retrofit中就是用注解来描述我们的请求行为:如请求方式、请求参数等,然后在运行期间,通过解析注解封装一个请求request,request中会携带请求头、请求地址、请求方式等信息,最终调用okhttp完成真正的请求。

总体来说,retrofit主要有三类注解:

1,描述网络请求方式的注解

@GET,@POST,@DELETE等

2,描述网络请求参数的注解

@HEAD,@Field,@Query等

3,其他类型注解

@Multipart,@Streaming,@FormUrlEncode

三,retrofit中的重要组件

查看retrofit的源码:

public final class Retrofit {
  final okhttp3.Call.Factory callFactory;
  final List<Converter.Factory> converterFactories;
  final List<CallAdapter.Factory> callAdapterFactories;
  final @Nullable Executor callbackExecutor;
      
  ...
}

上面列举了retrofit有几个重要的组件,我们可以使用retrofit默认提供的这些组件实现,或者在实例化retrofit的时候,给它设置我们自定义的组件实现,这些组件的具体原理在后面会详细讲解。

1,callFactory

自定义配置的okHttpClient,retofit本身实际上并没有进行网络请求的能力,它依赖OkHttp完成网络请求。

2,converterFactories

数据转换器,用来将okhttp返回的response转换成我们自定义的数据bean。

3,callAdapterFactories

适配器,适配器的返回值决定着上面步骤二中接口的返回值。

4,callbackExecutor

回调执行器,切换到主线程回调结果。

四,动态代理

上面步骤4 创建了描述网络请求接口的代理,代码如下:

val apiProxy = retrofit.create(HotKeyApiInterface::class.java)

查看retrofit#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);
            }
          });
}

create方法调用Proxy.newProxyInstance()为接口HotKeyApiInterface生成动态代理,Proxy.newProxyInstance()源码如下,它是java提供的动态创建代理的api,接受三个参数:

  1. classLoader:类加载器。
  2. interfaces: 接口的class数组,创建的动态代理会实现这里的接口。
  3. InvocationHandler:类InvocationHandler的一个实现,后面会分析这个类的作用。
public static Object newProxyInstance(
    @RecentlyNullable ClassLoader loader, 
    @RecentlyNonNull Class<?>[] interfaces, 
    @RecentlyNonNull InvocationHandler h) throws IllegalArgumentException {
       
       ...
}

上面的动态代理会生成一个代理类Proxy,这里的代理类并不是一个java文件,而是一个class文件,因为动态代理是在运行期间生成代理类的,代理类的class文件反编译成java文件后,代码大致如下。

//生成的代理类的源码
public final class $proxy0 extend Proxy implements HotKeyApiInterface {
    
    public $Proxy0(InvocationHandler handler) {
        super(handler);   //这里的handler就是上面我们传的第三个参数InvocationHandler,会赋值给它的父类Proxy的属性h
    }
    
    public final Call<ApiResult<List<Info>>> getDataWithCall() {
        this.h.invoke( ... ) //这里的h为上面传进来的第三个参数InvocationHandler
    }
    
    ...
}


//系统类Proxy的源码
public class Proxy implements Serializable {
    protected InvocationHandler h;
    
    ...
}

总结一下:上面声明的apiProxy为$Proxy0的实例,即动态代理生成的代理类继承自Proxy且实现了我们自定义的接口HotKeyApiInterface。

五,适配器CallAdapter

上面步骤5 创建网络请求Call的代码如下:

val call: Call  = apiProxy.getDataWithCall()

从前面文章的分析中可以知道,这里生成的apiProxy就是动态代理类 $Proxy0,它继承自Proxy且实现了接口HotKeyApiInterface,所以这里的调用流程为:

  1. 调用apiProxy#getDataWithCall方法。
  2. 即执行代理类的getDataWithCall方法。
  3. 步骤2的方法内部执行InvocationHandler的invoke方法,也就是会执行Retrofit#create方法中创建的InvocationHandler#invoke方法。

接着看InvocationHandler#invoke方法,源码如下:

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);   //关键点1
            }
          });
}

看关键点1处:执行loadServiceMethod方法的返回值invoke方法,即HtttpServiceMethod#invoke方法(怎么得出HtttpServiceMethod,大家可以自行调试):

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

//HtttpServiceMethod#adapter
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

所以,HtttpServiceMethod#adapter的返回值就是我们apiProxy.getDataWithCall()的返回值,adapter为一个抽象方法,它的实现类有三个:

  1. HtttpServiceMethod.CallAdapted:当apiProxy.getDataWithCall的返回值为Call的情况。
  2. HtttpServiceMethod.SuspendForResponse:这个是用来适配retrofit结合suspend,且返回值为Response的情况。
  3. HtttpServiceMethod.SuspendForBody:这个是用来适配retrofit结合suspend,且返回值为自定数据bean的情况。

上面的2, 3后续会单独出文章进行讲解,由于我们定义接口HotKeyApiInterface#getDataWithCall的返回类型为Call,所以这里HtttpServiceMethod#adapter方法的实现类为CallAdapter,看看它的源码:

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) {   //关键点1
    return callAdapter.adapt(call);    //关键点2
  }
}

上面代码的关键点1处:这里又有一个callAdapter,这个callAdapter才是我们要讲解的适配器CallAdapter,它在retrofit中的默认实现为:

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

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

    @Nullable
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        } else if (!(returnType instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
        } else {
            final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
            final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
            return new CallAdapter<Object, Call<?>>() {
                public Type responseType() {
                    return responseType;
                }

                public Call<Object> adapt(Call<Object> call) {   //关键点1
                    return (Call)(executor == null ? call : new ExecutorCallbackCall(executor, call));
                }
            };
        }
    }

看关键点1处,它返回一个ExecutorCallbackCall的实例,看它的源码:

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");

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

ExecutorCallbackCall实现了接口Call,是Call类型,它其实是一个代理类,包含着真正的Call(OkHttpCall,retrofit中的),它就是我们的apiProxy.getDataWithCall()的返回值。

六,网络请求Call

1,网络请求Call是什么

由前面的分析可知apiProxy.getDataWithCall()返回的是ExecutorCallbackCall,它的源码如下:

static final class ExecutorCallbackCall<T> implements Call<T> {
  final Executor callbackExecutor;
  final Call<T> delegate;  //关键点1

  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");

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

关键点1处:这个delegate是Retrofit中的OkHttpCall,源码如下:

final class OkHttpCall<T> implements Call<T> {
  private final RequestFactory requestFactory;
  private final Object[] args;
  private final okhttp3.Call.Factory callFactory;
  private final Converter<ResponseBody, T> responseConverter;

  private volatile boolean canceled;

  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;  //关键点2

  @GuardedBy("this") // Either a RuntimeException, non-fatal Error, or IOException.
  private @Nullable Throwable creationFailure;

  @GuardedBy("this")
  private boolean executed;
  
}

看关键点2处:这个rawCall是Okhttp中的call。

总结一下:

  1. apiProxy.getDataWithCall()返回的call是ExcutorCallbackCall。
  2. ExcutorCallbackCall持有Retrofit中的OkHttpCall。
  3. Retrofit中的OKhttpCall持有OkHttp的Call。
  4. Retrofit发起网络请求实际最终调用的是OkHttp的Call发起网络请求。