Retrofit源码阅读
Retrofit源码阅读

Retrofit是一个相当简洁的网络请求框架,其本质上只是对Okhttp的封装,实际上底层还是用Okhttp来执行网络请求。这两天终于比较闲一些,于是又想起了被我束之高阁的前辈的武功秘籍

Retrofit的使用

参考官方例子,定义接口并使用

  public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
  }

    // Create a very simple REST adapter which points the GitHub API.
    Retrofit retrofit =
        new Retrofit.Builder()
            .baseUrl(API_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // Create an instance of our GitHub API interface.
    GitHub github = retrofit.create(GitHub.class);

    // Create a call instance for looking up Retrofit contributors.
    Call<List<Contributor>> call = github.contributors("square", "retrofit");

    // Fetch and print a list of the contributors to the library.
    List<Contributor> contributors = call.execute().body();

源码阅读

首先来到梦的开始retrofit2.Retrofit#create,可以看到这里是个动态代理,后续的处理交给retrofit2.ServiceMethod#parseAnnotations

image-20220607204925036

而后ServiceMethod中解析注解中的信息

image-20220607205316353

继续阅读,果然在requestFactory的Builder中找到了@GET@POST等注解的处理。

继续HttpServiceMethod,暂时不看Kotlin Suspend Function部分,还是比较清晰的:就是处理了下call adapter,让请求的call对象转换到指定的线程工具上,如RxJava。

image-20220612235658307

CallAdapted继承自HttpServiceMethod,而在HttpServiceMethod我们找到了网络请求对象OkhttpCall。

然而OkhttpCall还是发起请求和处理响应的,发起请求还是用的RequestFactory。requestFactory是在上面解析注解时赋值的,很快找到了实际创建Okhttp对象的位置。

image-20220608152000407

然后Response对象的解析

image-20220608152330130

这里用responseConverter将原始的Response的body转换为解析好的Response对象。

啪,没了。


核心问题

如何自定义注解?

读取注解信息,用于请求参数。处理方法参考:retrofit2.RequestFactory.Builder#parseMethodAnnotation

如何将方法转化成Request对象?

借助动态代理实现接口定义方法,借助反射读取到方法形参和注解,借助形参类型和注解确定请求参数,最终在retrofit2.RequestFactory#create构建出实际的OkhttpRequest。

ServiceMethod的作用?

实现Okhttp Call到call adapter的委托。

adapter,converter的设计思路,如果想要实现将okhttp也变成可替换的应该如何设计代码?

Retrofit对象作为context,维护了各种所需参数和构造方法(factory)。在后续实际需要的位置创建出adapter。如可以定义NetlibAdapterFactory,RequestFactory中用到Okhttp的地方替换为由retrofit.netlibAdapterFactory创建。

InvocationHandler与泛型的使用?

object StubHelper {
    private const val TAG = "StubHelper"

    fun <T> create(service: Class<T>): T {
        return Proxy.newProxyInstance(
            service.classLoader, arrayOf<Class<*>>(service),
            object : InvocationHandler {
                private val emptyArgs = arrayOfNulls<Any>(0)

                @Throws(Throwable::class)
                override fun invoke(proxy: Any, method: Method, args: Array<Any>?): Any? {
                    Log.d(TAG, method.toGenericString())
                    return null
                }
            }) as T
    }
}

最后修改于 2022-06-09