Retrofit的内核原理解析

作者: Android架构 | 来源:发表于2019-03-05 21:30 被阅读17次

    简介

    Retrofit是目前比较流行的网络框架,它封装了okhttp作为底层的网络通讯框架, 使用动态代理方式来解析注解, 今天来扒一扒它的运行原理.
    通常Retrofit的使用分为如下四步:
    第一步: 定义网络接口

    public interface PostRequest_Interface {
        @POST("translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest=")
        @FormUrlEncoded
        Call<Translation1> getCall(@Field("i") String targetSentence);
    }
    
    

    第二步: 创建Retrofit

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://fanyi.youdao.com/") // 设置 网络请求 Url
                    .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                    .build();
    
    

    第三步: 创建代理对象

    PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);
    
    

    第四步: 创建Call对象

    Call<Translation1> call = request.getCall("I love you");
    
    

    第五步:执行异步网络请求

    call.enqueue(new Callback<Translation1>() {
                //请求成功时回调
                @Override
                public void onResponse(Call<Translation1> call, Response<Translation1> response) {
                    System.out.println(response.body().getTranslateResult().get(0).get(0).getTgt());
                }
    
                //请求失败时回调
                @Override
                public void onFailure(Call<Translation1> call, Throwable throwable) {
                    System.out.println("请求失败");
                    System.out.println(throwable.getMessage());
                }
            });
    
    

    下面通过解析源码来看看,整个内部实现原理是怎样的.
    我们从第二步代码开始

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://fanyi.youdao.com/") // 设置 网络请求 Url
                    .addConverterFactory(GsonConverterFactory.create()) //设置使用Gson解析(记得加入依赖)
                    .build();
    
    

    这里首先会实例化一个

    public Builder() {
          this(Platform.get());
    }
    
    
    Builder(Platform platform) {
          this.platform = platform;
          // Add the built-in converter factory first. This prevents overriding its behavior but also
          // ensures correct behavior when using converters that consume all types.
          converterFactories.add(new BuiltInConverters());
    }
    
    

    其实这就是以build模式创建一个Retrofit实例. 接下来我们看下第三步创建代理对象

    PostRequest_Interface request = retrofit.create(PostRequest_Interface.class);
    
    

    下面代码比较关键,也是Retrofit的精髓所在.

    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, @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);
                }
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
                ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    
    

    这段代码主要用到了动态代理,它通过newProxyInstance返回一个T类型的动态代理对象(实际上就是PostRequest_Interface),当我们调用

    request.getCall("I love you");
    
    

    实际上会执行invoke代理方法返回一个Object. 具体来看看他是怎么执行的呢。

    if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
                }
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
    
    

    通常上面这些代码一般都不会执行到,所以重点来看看下面的代码. 分为3步来看.

    1,ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
    2,OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    3,return serviceMethod.callAdapter.adapt(okHttpCall);
    
    

    1,创建一个ServiceMethod

      ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    
    

    ServiceMethod的创建是通过构造模式,构造函数中传入了method对象,在build过程中,有个比较关键函数,用于对method注解进行处理

    public ServiceMethod build() {
          //代码省略...
          for (Annotation annotation : methodAnnotations) {
                  parseMethodAnnotation(annotation);
          }
          //代码省略...
    }
    
    
    private void parseMethodAnnotation(Annotation annotation) {
          if (annotation instanceof DELETE) {
            parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
          } else if (annotation instanceof GET) {
            parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
          } else if (annotation instanceof HEAD) {
            parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
            if (!Void.class.equals(responseType)) {
              throw methodError("HEAD method must use Void as response type.");
            }
          }
          //代码省略...
    }
    
    

    2,创建OkHttpCall对象,传入刚才创建serviceMethod和args

      OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
      }
    
    

    3,用serviceMethod的callAdapter适配OkHttpCall然后返回一个T对象(此刻应该是PostRequest_Interface)

    serviceMethod如何进行适配的呢,首先Retrofit创建的时候有一个接口,提供CallAdapter的创建工厂

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
    }
    
    

    callAdapter也是一个成员变量,通过build模式创建

    final class ServiceMethod<R, T>{
            this.callAdapter = builder.callAdapter;
    }
    
    

    在Builder调用createCallAdapter

    static final class Builder<T, R> {
          public ServiceMethod build() {
              callAdapter = createCallAdapter();
          }
    }
    
    
    private CallAdapter<T, R> createCallAdapter() {
         return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
    }
    
    

    接着Retrofit中调用callAdapter,执行nextCallAdapter

      public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
      }
    
    
    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
    CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    }
    
    

    CallAdapter是从adapterFactories中获得. adapterFactories来自于2个地方,第一是调用

    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
    }
    
    

    第二是:

    adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
    
    CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        return DefaultCallAdapterFactory.INSTANCE;
    }
    
    
    final class DefaultCallAdapterFactory extends CallAdapter.Factory {
      static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
    
      @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
    
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public Call<Object> adapt(Call<Object> call) {
            return call;
          }
        };
      }
    }
    
    

    这个缺省的CallAdapter实现很简单,只是返回原来的call对象,没有做任何操作. 所以说上面

    return serviceMethod.callAdapter.adapt(okHttpCall);
    
    

    第四步中实际上返回的就是okHttpCall对象.
    第五步执行enqueue方法,实际上也是okHttpCall的enqueue方法

    public void enqueue(final Callback<T> callback) {
    if (call == null && failure == null) {
            try {
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
    
    call.enqueue()....
    //代码省略...
    }
    
    

    call来自于createRawCall

      private okhttp3.Call createRawCall() throws IOException {
        Request request = serviceMethod.toRequest(args);
        okhttp3.Call call = serviceMethod.callFactory.newCall(request);
        return call;
      }
    
    
    okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
    
    

    callFactory就是OkHttpClient, 在OkHttpClient中返回一个RealCall对象

    public Call newCall(Request request) {
        return new RealCall(this, request, false /* for web socket */);
    }
    
    

    RealCall就是okhttp提供的对象,接下来enqueue走的就是okhttp流程了.
    总的来说Retrofit只是一套解析接口注解转换为一个okhttp call,然后走okhttp流程的注解解析框架.

    最后

    在这里我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案做成了文档和架构视频资料免费分享给大家【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

    资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

    点击链接加入群聊【Android移动架构总群】:加入群聊

    资料大全

    相关文章

      网友评论

        本文标题:Retrofit的内核原理解析

        本文链接:https://www.haomeiwen.com/subject/cusauqtx.html