浅析 Retrofit 2 源码

最近新上了一个项目,用到了 Retrofit 2 + RxJava 与服务器进行交互。使用了一段时间后,对于其 Retrofit 的简洁、灵活印象深刻。尤其好奇的是其定义一个 HTTP 请求的方式,仅仅通过一个接口定义加上几个注解就完成了。虽然能大概推测到,一定是通过什么方法 将接口方法和注解包含的信息转化成了一个 HTTP Request ,但是对于背后具体的实现还是不清楚。于是就抽空研究了一下源码,发现代码量不大,但是设计思想真是精妙,值得好好学习一下。

为了让讲解更加的具体,将 用一个项目中实际用到的接口作为示例 一步步的进行分析,看看 Retrofit 是如何进行一个 HTTP 请求的。当然了,因为实际的 HTTP
请求处理是依赖于 okhttp 的,所以这一部分就不深入讲解了,以后有时间再单独开一篇来讲 okhttp 吧。

0. Retrofit 项目结构

  • http包:定义各种 @Get , @Post 等注解;
  • 两个核心类:RetrofitMethodHandler
    Retrofit 的主要逻辑和配置基本上通过这两个类来完成,所以后面的分析也主要围绕着两个类展开。其他的类涉及到的时候再简单介绍
    浅析 Retrofit 2 源码_第1张图片
    Retrofit 项目结构

1. 示例接口

public interface AppApi {
     /**
     * 根据用户id返回用户基本信息
     * @param uid 用户id
     * @return
     */
    @GET("api/v1/user/{uid}/")
    Observable getUser( @Path("uid") String uid );
}

这个接口功能非常简单,以用户id uid 作为参数发起请求,服务器会返回一个 json 字符串,这个字符串将被自动解析成一个 User 对象。当然前面提到用到了 RxJava,所以返回被转换成了一个可以产生 User 对象的 Observable,不过并不影响我们的分析。

2. 使用前的基本配置

使用 Retrofit 发起调用前的一些初始化配置如下。

  OkHttpClient httpClient = new OkHttpClient.Builder().build();
    
  Retrofit appRetrofit = new Retrofit.Builder()
          .client(httpClient)
          .baseUrl(BuildConfig.API_ENDPOINT)
          .addConverterFactory(GsonConverterFactory.create())
          .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
          .build();

发起一个 HTTP 请求

  AppApi appApi = appRetrofit.create(AppApi.class);

  Observable observable = appApi.getUser("1234567");

  observable
          .subscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(new Action1() {
              @Override
              public void call(User user) {
              //do something with user                    
          }
  });

上面这段代码的头两句背后的逻辑就是 Retrofit 的核心所在,接下来我们就一步步进行分析。

3. 创建动态代理对象

在上一节中,发起 HTTP 请求的第一句, 只调用了一个 Retrofit.create() 方法。

AppApi appApi = appRetrofit.create(AppApi.class);

Retrofit.create()方法的源码如下:

  public  T create(final Class service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, 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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadMethodHandler(method).invoke(args);
          }
        });  
  }

通过源码我们可以看到,这里实际的返回是通过
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler invocationHandler)
构造出来的一个 动态代理对象。这个方法前两个参数没什么好书偶的,第一个参数指定加载代理对象的 ClassLoader, 第二个参数就是需要被动态代理的接口数组,重点是第三个参数,它是一个 InvocationHandler 接口,需要实现它的 invoke() 方法。当通过动态代理对象调用接口的方法时,实际上最终就会调用 invoke() 方法。

关于 动态代理 的详细介绍可以参考这篇文章。这里引用其中关于动态代理的一个概述:

Java 动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。

如果一时还无法理解动态代理的概念,那么现在只需要记住两点:

  • AppApi appApi = appRetrofit.create(AppApi.class); 这里的 appApi 已经是一个动态代理对象;
  • appApi.getUser("1234567"); 动态代理对象调用的方法,最终都会去到 InvocationHandlerinvoke() 方法里。

那么再回到 Retrofit.create() 方法,我们重点要关注的就是 InvocationHandler.invoke() 方法的实现。前面两个 if 判断可以直接略过,关键就在最后一句 loadMethodHandler(method).invoke(args)
loadMethodHandler() 方法的源码如下:

  MethodHandler loadMethodHandler(Method method) {
    MethodHandler handler;
    synchronized (methodHandlerCache) {
      handler = methodHandlerCache.get(method);
      if (handler == null) {
        handler = MethodHandler.create(this, method);
        methodHandlerCache.put(method, handler);
      }
    }
    return handler;
  }

这个方法就是为我们的接口中的每一个方法生成一个 MethodHandlermethodHandlerCache 就是一个用来缓存 MethodHandler 对象的 Map,对于已经调用过的 method 直接从 methodHandlerCache 中取。
可以看到关键是 MethodHandler.create(this, method) 这句,生成了MethodHandler 对象。接下来就来分析 MethodHandler 的源码。

4. MethodHandler

首先要了解下 MethodHandler 类包含的几个属性:

  • okhttp3.Call.Factory callFactory:
    okhttp 库中定义的接口,用来获得一个 okhttp.Call 对象。callFactory 在默认情况下被初始化为一个 OkHttpClient;
  • RequestFactory requestFactory:
    包含一个 create() 方法,根据各种参数,构造一个 okhttp.Request
  • CallAdapter callAdapter:
    Retrofit 库中定义的接口,用来把一个 okhttp.Call 对象转化为其他类型。比如Retrofit.Builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 就配置了一个RxJavaCallAdapterFactory, 把一个 Call 转换为 Observable;
  • Converter responseConverter:
    Retrofit 库中定义的接口,用来解析 HTTP 响应和请求。Retrofit.Builder.addConverterFactory(GsonConverterFactory.create()) 就配置了一个GsonConverterFactory,可以把一个 json 格式的字符串响应转化为相应的对象。默认情况下会配置一个 BuiltInConverters ,只是简单的转换为字符串。

介绍完几个关键属性,再来看 MethodHandler.create(Retrofit retrofit, Method method)方法:

1.   static MethodHandler create(Retrofit retrofit, Method method) {
2.     CallAdapter callAdapter = createCallAdapter(method, retrofit);
3.     Type responseType = callAdapter.responseType();
4.     if (responseType == Response.class || responseType == okhttp3.Response.class) {
5.       throw Utils.methodError(method, "'"
6.           + Types.getRawType(responseType).getName()
7.           + "' is not a valid response body type. Did you mean ResponseBody?");
8.     }
9.     Converter responseConverter = createResponseConverter(method, retrofit, responseType);
10.    RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);
11.    return new MethodHandler(retrofit.callFactory(), requestFactory, callAdapter, responseConverter);
12.  }

可以发现就是根据传入的 retrofit 参数 和 method 参数来完成了前面提到的几个属性的初始化, nothing special. 唯一需要注意的是 第10行:

RequestFactory requestFactory = RequestFactoryParser.parse(method, responseType, retrofit);```
这里的 `RequestFactoryParser` 就是用来根据方法的注解、方法的参数等来解析出构造 `Request` 需要的信息,比如请求头部,请求方法,请求参数等。比较简单,就不深入了。

到这里,回顾一下我们的调用链:
  1. Retrofit.create() 构造动态代理对象;(` AppApi appApi = appRetrofit.create(AppApi.class);`)
  2. 动态代理对象调用方法 (`appApi.getUser("1234567");`)
  3. 方法调用实际被转化为 `InvocationHandler.invoke()`
  4. `loadMethodHandler()` 构造一个 `MethodHandler`

现在,离最终的调用只剩最后一步了 就是 `MethodHandler.invoke()` ,其实这个方法只有一句话...
```java
  Object invoke(Object... args) {
    return callAdapter.adapt(new OkHttpCall<>(callFactory, requestFactory, args, responseConverter));
  }

在这里终于见到了 HTTP 调用的真身 OkHttpCall, 而 callAdapter 对于我们的例子来说就是
RxJavaCallAdapterFactory.ResponseCallAdapter, 其定义的 adapt() 方法会把 OkHttpCall 转化为 Observable,这点本节开头已经讲过。

至此,一个从定义API接口到生成API请求的完整流程就走完了。不过要注意下,这里实际上还没有发起 HTTP 请求,只是准备好了发起一个 HTTP 请求所需要的一切。实际的请求在调用 OkHttpCall.execute() 或 enqueue() 的时候才会发起 ( 对于 Observable 类型的,是在Observable.subscribe() 的时候才发起 )

5. 结语

通过上面的分析可以看到,动态代理是 Retrofit 的核心所在,大量使用 Factory 模式使得 Retrofit 具备了模块化,可灵活配置的能力,而通过注解定义 HTTP 请求,使得代码可读性变得更高。真的是一旦上手,别无所求啊!

你可能感兴趣的:(浅析 Retrofit 2 源码)