TTNet | 青训营笔记

674 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第8天

TTNet

TTNet是字节跳动通用的网络请求封装框架,用来向服务端发起请求。

目前Android端上的头条,抖音,番茄小说都在使用该库作为网络请求封装框架,作为字节内部的基础库,提供了一整套Android客户端网络请求解决方案。

  • 它有哪些突出的优点:
    • 基于Retrofit改造,具备了Retrofit所具有的优点
    • 支持多个Http网络库的动态切换(okhttp和cronet)
    • 支持网络拦截配置:添加公共参数,动态切换协议及Host,动态选路等
    • 支持流解析,json序列化

为什么要做TTNet?

Retrofit作为网络封装框架,已经足够优秀了,那么我们为什么还要基于Retrofit改造做我们自己的TTNet网络封装框架呢?

Retrofit是开源的网络框架,我们只能被动依赖,无法主动修改以适应我们的业务发展。如:Retrofit只支持OkHttp网络库,不支持其他网络库。

那么,问题来了。我们有更优秀的网络库cronet,我们想使用它,但是我们又迷恋Retrofit的优秀的封装特性和接口调用的简易特性?

答案:打造自己维护的网络框架 TTNet

TTNet与Retrofit的使用对比img

img

Retrofit使用OkHttp的流程介绍

Retrofit的主流程
Retrofit调用底层OkHttp的方式

在主流程图中,okhttp网络库的api,在Retrofit中是何时发起请求的,对应api已列出,相同颜色即意味着调用关系。

如:

绿色代码:标记1处,创建Retrofit对象时,对应创建了OkHttpClient对象;

红色代码:标记4处,使用RetrofitCall对象发起请求时,对应创建OkHttp网络库中Request对象和Call对象并发起请求。

Retrofit里的OkHttpClient的调用时机

public void getRequest() { Retrofit retrofit = new Retrofit.Builder() .baseUrl("www.bytedance.com/") //.addCallAdapterFactory(okhttp3.Call.Factory) .build() ; // 标记(1) }

// Retrofit$Builder public Retrofit build() { okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient() ; // 标记(2) } List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); // platform为Android的实例 // 集合里的实例为ExecutorCallAdapterFactory的实例。这里要留意下 adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }

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

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

// Retrofit public final class Retrofit { private final okhttp3.Call.Factory callFactory; Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories, Executor callbackExecutor, boolean validateEagerly) { this .callFactory = callFactory; // 标记(3) } }

OkHttpClient对象的创建,我们已经看到了。那么创建好之后,在何处完成调用呢? 我们往下走,答案就在下面的流程梳理里面。

不过,我们先留意下,adapterFactories集合里的对象。里面有一个默认的CallAdapter.Factory实例,它就是子类ExecutorCallAdapterFactory的实例。我们在后续解析请求方法时,会用到它。

OkHttpCall的创建

当我们通过代理对象调用我们的接口方法IUserNameService#getUserName时,会触发InvocationHandler#invoke方法

 public void getRequest(){
     Retrofit retrofit = new Retrofit.Builder()
             .baseUrl("https://www.bytedance.com/")
             .build();
     IUserNameService iUserNameService = retrofit.create(IUserNameService.class);
     // 标记1
     Call<ResponseBody> call = iUserNameService.getUserName( 1123 );
 }
 ​
 // Retrofit
 public <T> T create(final Class<T> service) {
   
   return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
       new InvocationHandler() {
         private final Platform platform = Platform.get();
         // 标记(2)
         @Override public Object invoke(Object proxy, Method method, Object... args) {
           ServiceMethod serviceMethod = loadServiceMethod(method);
           OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
           return serviceMethod.callAdapter.adapt(okHttpCall);
         }
       });
 }

我们需要重点关注invoke方法中OkHttpCall对象的创建,serviceMethod.callAdapter.adapt(okHttpCall)中方法调用的实现,serviceMethod.callAdapter.adapt(okHttpCall)的返回值。一会儿会用到

okhttp.Request对象和okhttp.Call对象的创建及请求发起
 public void getRequest(){
     Retrofit retrofit = new Retrofit.Builder()
             .baseUrl("https://www.bytedance.com/")
             .build();
     IUserNameService iUserNameService = retrofit.create(IUserNameService.class);
     // call对象的取值为InvocationHandler#invoke()方法的返回值,默认为ExecutorCallbackCall对象
     Call<ResponseBody> call = iUserNameService.getUserName(1123);
     // 标记1: 由请求物料的封装过程,我们知道 call为ExecutorCallbackCall的实例
     call.enqueue(new Callback<ResponseBody>() {
         @Override
         public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
 ​
         }
 ​
         @Override
         public void onFailure(Call<ResponseBody> call, Throwable t) {
 ​
         }
     });
 }
 ​
 // Retrofit
 public <T> T create(final Class<T> service) {
   
   return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
       new InvocationHandler() {
         private final Platform platform = Platform.get();
         // 标记(2)
         @Override public Object invoke(Object proxy, Method method, Object... args) {
           ServiceMethod serviceMethod = loadServiceMethod(method);
           OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
           return serviceMethod.callAdapter.adapt(okHttpCall);
         }
       });
 }
 ​
 // ExecutorCallbackCall
 @Override 
 public void enqueue(final Callback<T> callback) {
     // ExecutorCallbackCall实例所拥有的delegate为OkHttpCall对象。
   delegate.enqueue(new Callback<T>() {
     @Override 
     public void onResponse(Call<T> call, final Response<T> response) {
       // ...
     }
   });
 }
 ​
 //OkHttpCall 这里的内容是不是似曾相识,没错它就是OkHttp完成请求的过程。我们上面已贴出
 public void enqueue(final Callback<T> callback) {
   // 这里完成的了Request的创建
 Request request = serviceMethod.toRequest(args);
  // 这里完成了Call对象的创建
 okhttp3.Call call = serviceMethod.callFactory.newCall(request);
   // 通过call对象发起异步请求
   call.enqueue( new okhttp3.Callback() {
  @Override 
  public  void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
 throws IOException {
 Response<T> response = parseResponse(rawResponse);
 callSuccess(response);
 }
 ​
  @Override 
  public  void  onFailure ( okhttp3.Call call, IOException e ) {
 callback.onFailure(OkHttpCall.this, e);
 }
 ​
 });
 }
 ​
 // ServiceMethod
 Request toRequest(Object... args) throws IOException {
   RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
       contentType, hasBody, isFormEncoded, isMultipart);
 ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
   for (int p = 0; p < argumentCount; p++) {
     handlers[p].apply(requestBuilder, args[p]);
   }
   return requestBuilder.build();
 }

OkHttpCall#enqueue方法里,通过ServiceMethod#toRequest方法,完成了Request的创建。因为ServiceMethod拥有接口方法IUserNameService#getUserName的全部请求物料信息,传入请求实参后,便可直接构造request对象。

构建完request对象后,serviceMethod.callFactoryOkHttpClient实例。通过OkHttpClient#newCall方法构建Call对象。

构建Call对象完成后,通过Call对象发起异步请求。

请求完毕后,返回响应对象Response。到此OkHttp请求调用过程完毕。

到这里Retrofit只支持OkHttp网络库就得到了解答:

通过代理对象对方法接口进行调用时,会在InvocationHandler#invoke方法回调里为serviceMethod.callAdapter.adapt()设置okHttpCall对象,进而发起请求时,委托OkHttpCall对象发起网络请求。而OkHttpCall#enqueue 调用okHttp网络库发起请求。

所以serviceMethod.callAdapter.adapt()设置死了为okHttpCall对象。Retrofit发起请求只能对OkHttp网络库进行支持了。

 public <T> T create(final Class<T> service) {
   
   return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
       new InvocationHandler() {
         private final Platform platform = Platform.get();
         // 标记(2)
         @Override public Object invoke(Object proxy, Method method, Object... args) {
           ServiceMethod serviceMethod = loadServiceMethod(method);
           OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
           return serviceMethod.callAdapter.adapt(okHttpCall);
         }
       });
 }

所以我们要支持多个网络库的改造,那么就在**OkHttpCall** 的改造上做文章就好。

总结

  • 关于命名的大多数规范核心在于考虑上下文
  • 人们在阅读理解代码的时候也可以看成是计算机运行程序,好的命名能让人把关注点留在主流程上,清晰地理解程序的功能,避免频繁切换到分支细节,增加理解成本