Retrofit源码解析(一)

443 阅读3分钟

调用流程

Retrofit retrofit = new Retrofit.Builder()

        .baseUrl("https://api.github.com/")

        .addConverterFactory(GsonConverterFactory.create())

        .build();

GithubService service = retrofit.create(GithubService.class);

Call<List<Repo>> repos = service.listRepos("byerman");

repos.enqueue(new retrofit2.Callback<List<Repo>>() {

    @Override

    public void onResponse(Call<List<Repo>> call,retrofit2.Response<List<Repo>> response) {}                                 

    @Override

    public void onFailure(Call<List<Repo>> call, Throwable t) {}

});

目标一:如何完成一个网络请求的基本链路?

1.repos.enqueue(new Callback()) 通过调用Call.enqueue,在内部函数的回调中获得网络请求的结果 等待repos的返回

2.去看一下enqueue内部实现,发现Call是一个接口,所以要去看一下Call是怎么来的?service.listRepos("byerman") 

   发现listRepos也是一个接口调用,所以去看一下service是怎么来的?retrofit.create(GithubService.class) : 等待service的返回

3.查看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);

            }

          });

}

validateServiceInterface(service) 

含义:检查service可用性、预加载

  • 检查传进来的Class,如果不是接口类,则抛出异常
  • 遍历service及其父接口,如果有泛型声明,则抛出异常
  • 通过配置validateEagerly 提前解析method,提前发现代码异常
Proxy.newProxyInstance(service.getClassLoader(),

          new Class<?>[] {service},

          new InvocationHandler())

含义:

通过动态代理,当调用目标对象(接口类)的方法时,通过动态代理的invoke方法,获取真实的代理对象并返回给我们

这里我们关注

loadServiceMethod(method).invoke(args) : 返回我们需要真实的Call对象(代理对象) 

platoform.invokeDefaultMethod(method,servicec,proxy,args)只是把类的默认方法不处理,直接返回而已

到这里我们的第一条链路就结束了

目标:完成一个网络请求的链路

过程:

repos.enqueue(new Callback())  repos怎么来的?repos:Call对象

service.listRepos->通过动态代理invoke回调类调用实际代理类的方法获取repos

loadServiceMethod(method).invoke(args)返回我们需要的repos(Call)对象

结果:通过调用Call.enqueue,在回调函数中获取返回的数据

目标二:Call是一个接口,enqueue是接口方法,它们内部的具体实现类是怎样的?(目标一的扩展,通过具体实现类才能知道实际是怎么完成网络请求的)

因为这里返回的Call是一个接口,通过上一个分析我们知道

loadServiceMethod(method).invoke(args)可以得到我们需要的Call对象

接下来分析这个方法,首先看invoke

Image.png

发现是一个抽象的方法,具体实现要找到具体实现类,看里面的invoke的逻辑

所以看loadServiceMethod(method)

Image.png 这里serviceMehtodCache是一个Map集合(有缓存的作用),key是Method,我们关注没有缓存的情况1

ServiceMethod.parseAnnotations(this,method)

跟踪代码

Image.png 继续跟踪,我们主要看return方法,细节不急着看,下面的HttpServiceMethod.parseAnnotations最后的代码

Image.png

可以看到当代码支持kotlin时,返回下面两个内容,我们只关注java,所以看CallAdapted那块内容

Image.png

这里终于找到ServiceMethod的最终实现类了,但是没发现invoke方法,所以回到HttpServiceMethod看有没有invoke(如无意外肯定有,因为没其他类了) Image.png 可以看到我们要找的Call就是OkHttpCall了,然后return的时候调了adapt对call进行处理,返回一个新的Call(这里为了不混淆我们目标,因为跟踪代码后会发现,最后返回的Call还是这个OkHttpCall),所以我们继续看call里面的enqueue方法 Image.png 这里创建了一个okhttp3的call对象,并把rawCall赋值给它,因为初始化时rawCall是空的,最后createRawCall创建新的Call Image.png 最后通过okhttp3的Call.enqueue进行网络请求,在onResponse和onFailed中得到请求结果,并调用我们传进来的callback对象把结果回调出去,至此,整个流程完成,我们可以知道,最后Retrofit也是调用了Okhttp的Call对象enqueue得到结果,整理一下流程图

Image.png

目标三:adapt(call,args)内部对OkHttpCall做了什么处理,OkHttpCall传入的参数requestFactory, args, callFactory, responseConverter如何生成?

敬请关注下一篇文章内容