Retrofit2.0源码解析

Retrofit 是square公司开发的一款对OKHttp进行了进一步封装的网络框架,现在也是android网络请求中非常火的一个网络请求框架,最近在准备面试的时候也刚好复习到了这一块,然后花了几天时间简单地看了下Retrofit2.0源码,分享一下。若有不对的地方,欢迎指正。

Retrofit2.0原理

Retrofit2.0用了动态代理技术,通过解析注解生成Http请求,把请求交给OkHttp,然后通过我们设置的ConverterFactory进行serialization和deserialization,最后通过CallAdapter把结果进行进一步适配,实现了对Rxjava,Guava和java8的支持。


Retrofit2.0所使用的动态代理

在官方给的samples中,我们首先得创建一个retrofit对象,然后通过该对象创建一个我们要代理的实例,即:

 public static final String API_URL = "https://api.github.com";
 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);

这个Github就是我们网络请求的接口:

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

在这里,retrofit使用了builder模式,我们可以在此设置请求的URL,ConverterFactory(此处用了Gson解析,当然你也可以自定义数据解析器,只要你的解析器继承 Converter.Factory就行),或者设置回调时的适配器。在retrofit中提供了三种CallAdapterFactoryGuavaCallAdapterFactoryJava8CallAdapterFactoryRxJavaCallAdapterFactory。比如要把response封装成rxjava的Observeble,然后对其进行流式操作:

Retrofit.Builder.addCallAdapterFactory(newRxJavaCallAdapterFactory().create());

然后我们点进去retrofit.create(GitHub.class)会发现:

 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> 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 (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            //对java8兼容
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            //看缓存里面有没有这个method,要是有,就返回,要是没有,就生成一个,然后加入缓存
            ServiceMethod serviceMethod = loadServiceMethod(method);
            //生成一个OkHttpCall对象
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            //调用OkHttp,然后根据okHttpCall返回rejava的Observe对象或者返回Call
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

这里的Platform 其实是检测retrofit所运行的平台,是java8还是android还是ios。这里主要是在builder的时候,如果没有设置适配器,那么retrofit就会通过运行时的不同平台,然后选择不同的CallAdapterFactory。从上面的代码可以看出,create 方法返回了一个动态代理对象,通过Github接口生成代理类,并将代理类的实现交给 InvocationHandler 作为具体的实现。这里使用动态代理的好处是简化复杂的网络请求和解析、封装ServiceMethod。

主要的网络请求类

OkHttpCall:这个类主要实现了Call<T>接口,主要的作用就是发送一个HTTP请求,retrofit默认的也是这个类,我们也可以根据不同的情况实现自己的Call类,这种设计很插件化。在OkHttpCall内部提供了异步和同步两种方法来发送请求,分别是同步的OkHttpCall.execute()和异步的OkHttpCall.enqueue(),在异步操作中:

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");
    okhttp3.Call call;
    Throwable failure;
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }
    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }
    if (canceled) {
      call.cancel();
    }
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callFailure(Throwable e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

这里的call就是okhttp3.Call,在这里通过用call.enqueue(...)把请求交给okhttp的队列中,然后再通过异步回调切换到主线程,这里线程切换主要是通过前面的retrofit在build()的时候,Platform检测到运行环境在android的时候,就会跳到Android:

 static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }

看到上面的MainThreadExecutor 就能看出来,在execute()的时候,retrofit获取了主线程的handler,然后在UI线程执行网络请求回调后的数据显示等操作。

网络请求流程总结

  • 首先,在Retrofitbuild的时候,我们假设设置了newRxJavaCallAdapterFactory().create(),还加上了addConverterFactory(GsonConverterFactory.create())
  • 在当我们调用github.contributors("square", "retrofit");的时候,其实是调用了动态代理的InvocationHandler,在InvocationHandler中,我们看到有一个ServiceMethod,这里用了缓存,缓存了之前调用过的网络请求的方法,loadServiceMethod(method)方法检测缓存里面有没有调用过这个method,要是有,就返回,要是没有,就生成一个(此时会解析contributors(),解析我们在contributors()上面加的Annotation等,以便后面封装成request),然后加入缓存。
  • 然后生成一个OkHttpCallserviceMethod.callAdapter.adapt(OkHttpCall),此时的callAdapter就是RxJavaCallAdapterFactory
  • InvocationHandler中的最后一行代码中, return serviceMethod.callAdapter.adapt(okHttpCall);此时调用了RxJavaCallAdapterFactory.adapt()方法,返回我们想要的对象,比如android里面默认的Call<>,或者我们这里设置了RxJavaCallAdapterFactory,所以返回的是Observable<>。
  • 当我们调用了rxjava的subscribe方法的时候(或者调用Call的enqueue方法) ,做了下面几件事:
    • 首先执行okHttpCall的execute()方法把网络请求交给okHttp,当完成请求后,会对网络请求的结果进行解析,在解析时,会调用serviceMethod.toResponse(catchingBody)这里会通过我们之前设置的GsonConverterFactory来解析返回的数据(比如通过GSON解析什么的),然后再生成一个Response类.
    • 再回调到ExecutorCallAdapterFactory(这个CallAdapterFactory是之前在retrofit的build()方法中通过Platform检测环境,然后设置的一个CallAdapterFactory),这个CallAdapterFactoryadapt()中生成了一个ExecutorCallbackCall对象,在这个ExecutorCallbackCallenqueue(CallBack)中,会调用MainThreadExecutorexecute()方法,此时就是之前说的利用handler切换到主线程。

    • 最后因为我们使用了rxjava,所以在这里会对返回的call对象进行了进一步封装,生成了我们需要的Observable<Response>,最后我们就可以在主线程中进行开心的rx的流式操作了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值