您的当前位置:首页Retrofit 源码解析的初次尝试

Retrofit 源码解析的初次尝试

2024-12-13 来源:哗拓教育
enter image description here

目录

  • Retrofit 简介
  • Retrofit 的具体使用
  • 重点分析

Retrofit 简介

Retrofit 是 Square 推出的 HTTP 框架,主要用于 Android 和 Java。Retrofit 将网络请求变成方法的调用,使用起来非常简洁方便。

  • Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
  • define how requests are made. Create instances using {@linkplain Builder
  • the builder} and pass your interface to {@link #create} to generate an implementation.

这是源码开头的解释,大致意思是 Retrofit 利用方法上的注解接口转化成一个 HTTP 请求。


Retrofit 的使用
  1. 首先建立API接口类:
public interface ZhihuApi {
    String HOST = 
    @GET("4/news/latest")
    Call<ZhihuList> getZhihuListNews(int page);
}
  1. 具体使用过程:
 // 创建 Retrofit 实例
 Retrofit retrofit = new Retrofit.Builder()
     .baseUrl(ZhihuApi.HOST)
     .addConverterFactory(GsonConverterFactory.create())
     .build();

 // 生成接口实现类
 ZhihuApi zhihuApi = retrofit.create(ZhihuApi.class);

 // 调用接口定义的请求方法,并且返回 Call 对象
 Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);

 // 调用 Call 对象的异步执行方法
 call.enqueue(Callback callback)

Retrofit 的重点解析
  1. Retrofit 的创建( Builder 模式)
 // 用于缓存解析出来的方法
  private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
  // 请求网络的 OKHttp 的工厂,默认是 OkHttpClient
  private final okhttp3.Call.Factory callFactory;
  // baseurl
  private final HttpUrl baseUrl;
  // 请求网络得到的 response 的转换器的集合 默认会加入 BuiltInConverters    
  private final List<Converter.Factory> converterFactories;
  // 把 Call 对象转换成其它类型,如 Call 以及 Observer
  private final List<CallAdapter.Factory> adapterFactories;
  // 用于执行回调 Android 中默认是 MainThreadExecutor
  private final Executor callbackExecutor;
  // 是否需要立即解析接口中的方法
  private final boolean validateEagerly;

以上是几个 Retrofit 中比较关键的变量,每个都有注释,一看便知。接下来看一看 内部类 Builderbuild()方法:

public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
      // 默认创建一个 OkHttpClient
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
      // Android 中返回的是 MainThreadExecutor
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      //adapterFactories 把 Call 对象转换成其他对象,如 Observer
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      // 请求网络得到的 response 的转换器的集合
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
  }

以上代码可以看出:callAdapter 是请求返回的对象,Converter 是转换器,转换请求的响应到对应的实体对象,OkHttpClient 是具体的 OkHttp 的请求客户端,在创建 Retrofit 的时候,如果没有指定 OkHttpClient,会创建一个默认的。如果没有指定 callbackExecutor,会返回平台默认的,在 Android 中是 MainThreadExecutor,并利用这个构建一个 CallAdapter 加入 adapterFactories

  1. Create() 方法
    有了 Retrofit 对象后,便可以通过 create() 方法创建网络请求接口类的对象。直接上代码:
public <T> T create(final Class<T> service) {
    // 检查传入的类是否为接口并且无继承
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      // 提前解析方法
      eagerlyValidateMethods(service);
    }
    // 重点是这里
    // 首先会返回一个利用代理实现的 ZhihuApi 对象
    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 the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // 为了兼容 Java8 平台,Android 中不会执行
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

            // 解析方法 这里用到了注解(Runtime)
            ServiceMethod serviceMethod = loadServiceMethod(method);
            // 将刚刚解析完毕包装后的具体方法封装成 OkHttpCall ,你可以在该实现类找到 okhttp 请求所需要的参数
            // 所以它是用来跟 okhttp 对接的。
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
             // 将以上我们封装好的 call 返回给上层,这个时候我们就可以执行 call 的同步方法或者异步进行请求。
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

这里使用的是 动态代理模式 ,简单的描述就是Proxy.newProxyInstance 根据传进来的 Class 对象生成了代理类,当这个代理类执行某个方法时总是会调用 InvocationHandler(Proxy.newProxyInstance 中的第三个参数) 的invoke方法,在这个方法中可以执行一些操作(这里是解析方法的注解参数等),通过这个方法真正的执行我们编写的接口中的网络请求。我们再来理一下思路:
Create() -->
return (T) Proxy.newProxyInstance(...){...}-->
Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);-->
public Object invoke(...){...}调用代理类的invoke()
记住动态代理,是在方法调用时才会真正的触发过程。

  1. ServiceMethod
    下面看一下在 invoke 中解析网络请求方法的几行,ServiceMethod serviceMethod = loadServiceMethod(method);代码如下:
 ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      // 从缓存中获取该方法
      result = serviceMethodCache.get(method);
      if (result == null) {
        // 为空就创建并且加入缓存
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

Retrofit 有一个双链表用来缓存方法
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();避免一个网络请求在多次调用的时候频繁的解析注解,毕竟注解解析过程消耗比较大。这个部分重点在ServiceMethod.Builder(this, method).build();
build()源码很长,只截取重点:

// 用来发送请求的 client
callAdapter = createCallAdapter();
...
// 结果的转换器(Gson,FastJson …)之类
responseConverter = createResponseConverter();

// 遍历解析注解
for (Annotation annotation : methodAnnotations) {
   parseMethodAnnotation(annotation);
}
...省略代码
  1. OkHttpCall

在得到 ServiceMethod 对象后,把它连同方法调用的相关参数传给了 OkHttpCall 对象,就是前面的这行代码:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

这个OkHttpCall才是真正OkHttp请求的回调,但是针对我们使用的不同的回调,比如:RxJava的Observable、Call,所以有一层转换的关系,把OkHttpCall转成对应的Observable和Call。就是serviceMethod.callAdapter.adapt(okHttpCall)的工作。

那么CallAdapter是干嘛的呢?上面调用了adapt方法,它是为了把一个Call转换成另一种类型,比如当 Retrofit 和 RxJava 结合使用的时候,接口中方法可以返回 Observable<T>,这里相当于适配器模式。默认情况下得到的是一个 Call对象,它是ExecutorCallbackCall,代码如下:

@Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

以上代码是在ExecutorCallAdapterFactory类中,这个类继承自CallAdapter.Factory,可以看到adapt()方法接受一个Call对象,看下ExecutorCallbackCall的部分源码:

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }
        ...省略
  }

enqueue 方法中,调用了 OkHttpCallenqueue,所以这里相当于静态的代理模式。OkHttpCall 中的 enqueue其实又调用了原生的OkHttp中的 enqueue,这里才真正发出了网络请求,部分代码如下:

@Override public void enqueue(final Callback<T> callback) {
    if (callback == null) throw new NullPointerException("callback == null");
    //真正请求网络的 call
    okhttp3.Call call;
    Throwable failure;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      //省略了部分发代码
      ...
      call = rawCall;
      //enqueue 异步执行
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
        //解析数据 会用到 conveterFactory,把 response 转换为对应 Java 类型
          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();
    }
  }
 });
}

OkHttp 获取数据后,解析数据并回调callback响应的方法,一次网络请求便完成了。

显示全文