Retrofit 源码学习

Retrofit的对象是通过建造者模式构建出来的

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

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    // 如果未设置Okhttp 对象,那么使用默认的
    callFactory = new OkHttpClient(); 
  }
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }
  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // Make a defensive copy of the converters.
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

在项目中我们定义了 TestService 这个接口

public interface TestService {
    @GET("xxxx/{path}/data")
    Call<String> getData(@Path("path") String path);
}

当我们需要使用TestService 的时候只需要调用 retrofit.create 方法。

service = retrofit.create(TestService.class);

就会得到一个TestService 的实例。

进入create 方法

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 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)) { // 源码中始终返回false.
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }

        ServiceMethod serviceMethod = loadServiceMethod(method);
        OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return serviceMethod.callAdapter.adapt(okHttpCall);
      }
    });
}

eagerlyValidateMethods(service);

这个方法会把service中所有的方法放在 Retrofit 实例的 Map serviceMethodCache 对象当中,供以后的调用。validateEagerly 这个参数的作用就是判断是否在首次创建Retrofit 的时候就把所有的方法都放到这个map当中,如果不是就是使用到的时候再放进去

这个Map 中的key 是 Method 对象,而key 是SerivceMethod 这个对象中包含了很多东西,例如baseURL, relativeUrl, headrs 等信息,可以看看源码,ServiceMethod 对象同样是通过建造者模式创建的,创建的过程如下

  1. 创建一个 CallAdapter 对象
  2. 检查返回值类型,如果没有给定泛型中的具体类型,那么会抛出异常,例如直接返回Call 会抛出一个异常。
  3. 设置Response body 的转换器。
  4. 开始解析添加在方法上的注解,其中的注解包括了Http Method, Path, Header等信息,如果其中还包含Query Sring ,还会检查query string 是否不正确的使用@Path 注解。
  5. 然后再次检查是否没有添加表示Http Method的注解
  6. 检查是否有请求体,如果没有请求体,但是请求需要提交表单 那么会抛异常。
  7. 检查参数的类型,参数不能为表示泛型的通配符,必须是具体的类型
  8. 检查方法参数的注解,如果没有添加方法参数的注解会抛异常。
  9. 检查注解和方法参数注解的匹配,和使用规范注解(例如一个参数只能有一个注解)

方法的最后通过动态代理的方式返回了一个实现了 service 代表接口的类。

这里说一下动态代理匿名内部类中 Platform, 这个对象实际上表示了不同平台,目前里面默认的有Java, Android,IOS, 根据不同的平台会有一些不同地方,例如默认的回调池, CallAdapter 如何创建(后面分析)等等。

ServiceMethod serviceMethod = loadServiceMethod(method);

这一行代码就是前面提到的从 serviceMethodCache 这个map 对象中去取对应的方法。
之后创建了一个OkHttpCall 对象,OkHttpCall 实现了 Call 这个interface,进入到Call 这个interface中,上面有一段对这个类的注释:

Call最终代表了Retrofit 发送请求到服务器然后从服务器接受一个响应,每一个call产生自己的请求和和响应,可以通过clone方法来多次实现多次请求,通过这种方式可以实现轮询或者请求失败的重试。Call 通过enqueue方法来实现异步的调用,也可以使用 execute() 来实现同步的调用,当call正在读响应或者发请求的时候可能会有IOException.

读完这段之后,我们再来看 OkHttpCall 就会明白 OkHttpCall 只是 使用OkHttp来实现发送请求,所以Retrofit 并不是一个真正发送网络请求的库,真正实现网络请求的是okhttp,Retroif 只是在在上面实现了一层封装,提供了接口。

我们接着看 return serviceMethod.callAdapter.adapt(okHttpCall);

这里调用CallAdpater的adapt 方法返回了一个对象。

CallAdapter 是一个接口。

public interface CallAdapter<T> {
      Type responseType();
      <R> T adapt(Call<R> call);
}

其中定义两个方法,从方法的文档中可以知道 responseType 返回响应泛型的具体类型,在TestService中就是String, 而 adapt 方法就是真正产生返回值 Call的, 在文档里面说:这个方法实际上产生了 参数 call 的 一个代理。我们可以通过自定义自己的CallAdapter并且在retrofit对象构建的过程中传入,Retrofit 提供了一个默认的CallAdapter.

这个 callAdapter 对象创建的关键是在retrofit build过程中的 adapterFactories, 这是一个 CallAdapter 对象的List.

我们再回到Retrofit 的 build 方法当中

Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

callbackExecutor 这里返回对象不为空,会返回一个 MainThreadExecutor

static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());
    @Override 
    public void execute(Runnable r) {
        handler.post(r);
    }
 }

这个熟悉android Handler 的一看就知道了

接下来看 platform 对象的 defaultCallAdapterFactory 方法, 传入了 callbackExecutor

这里 platform 对象实际上 是 Android

static class Android extends Platform {
    ....    
    @Override 
    CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    ....
}

所以真正的 CallAdaterFactory (工厂模式创建CallAdater)在这里被构造出来。接着看 ExecutorCallAdapterFactory

贴关键代码

class ExecutorCallAdapterFactory extends CallAdapter.Factory {
    ...
  @Override
  public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Call<?>>() {
    ...
      @Override public <R> Call<R> adapt(Call<R> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

这里又是一个匿名内部类,关键的adapt 方法返回了 ExecutorCallbackCall 对象。

接着看 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()) {
            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
          } else {
            callback.onResponse(ExecutorCallbackCall.this, response);
          }
        }
      });
    }

    @Override public void onFailure(Call<T> call, final Throwable t) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });
}
....

首先 ExecutorCallbackCall 这个类也是一个Call对象,只用看enqueue 方法,方法的实现全部都是用调用了delegate,所以这里就知道了之前CallAdapter 接口文档里面写的 adapt 方法返回的只是 adapt 方法参数 call, 的一个包装类,这里的 delegate 就是call 对象。在这个回调里面也通过 callbackExecutor (MainThreadExecutor)实现了将callback 放到主线程里面来调用。

分析完了callAdapter.adapt 的方法,知道他返回的是一个 OkhttpCall的包装类。

再接着看OkhttpCall, 看异步发送请求的实现,

@Override
public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "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() {
        .....
    });
}

① 首次执行的时候,rawCall 和 creationFailure 都为空,这个是需要创建 rawCall , 也就是okhttp3.Call 的对象,进入到 createRawCall() 方法

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

}

先通过serviceMethod 创建了一个 Request 对象,

Request toRequest(Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
  throw new IllegalArgumentException("Argument count (" + argumentCount
      + ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
  handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}

实际上在这里,根据我们自定义service中的方法的参数来创建了一个Okhttp 中的请求对象Requestd,其中需要注意的是, 这个构造其中的过程中完成了对配置的各项参数的处理,其中ParameterHandler 是一个抽象类,继承这个类的类需要实现

abstract void apply(RequestBuilder builder, T value) throws IOException;

看一下Path 参数是如何被处理的,代码如下

static final class Path<T> extends ParameterHandler<T> {
    ....
    @Override 
    void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException(
            "Path parameter \"" + name + "\" value must not be null.");
      }
      builder.addPathParam(name, valueConverter.convert(value), encoded);
    }
}

最终是在 builder.addPathParam(name, valueConverter.convert(value), encoded);完成了对name(定义在url中的{name})替换。

最后调用requestBuilder.build() 完成了okhttp request 对象的创建。

在看到 createRawCall 方法当中,接下来需要用 okhttp 的 request 对象创建一个Call 对象,
接下来进入到 service.callFactory 的 newCall方法当中,这个方法最终的实现在OkHttpClient 这个类中,newCall直接创建了 RealCall 对象。

final class RealCall implements Call {...}

看到 RealCall 这个对象的声明,可以看出来实际上 OkHttpCall 是一个包装类,最终实现请求的是 RealCall。

那么实际上OkHttpCall实现的Call的各种方法实际上都是调用RealCall的实现来完成的。

再回到OkhttpCall 的enqueue 方法当中,如果上述的创建请求对象的过程中出错了,那么直接调用回调的onFailure 方法。

接下来 会调用call的 enqueue 方法,从上面的分析可以知道 call 实际上是 RealCall的一个对象,我们直接到RealCall中去看 enqueue 方法的实现。

RealCall 内部重载了enqueue

void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));}

关键是调用 client.dispatcher().enqueue() 这个方法,

因为这个里面就涉及到 okHtpp 源码的分析,就不再深入的分析,只是简单的看下里面的代码:

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }

}

AsyncCall 是一个Runnable 的对象,最终放到通过executorService方法得到的线程池中来执行。
不过放进去之前先判断一下当前正在执行的请求是否超过了限制,还有判断当前运行的请求队列是否有过多(大于maxRequestsPerHost)的request 请求同一个host ,如果不满足就放到等待队列中。

当请求完成的代码,是在AsyncCall当中。

Override 
protected void execute() {
  boolean signalledCallback = false;
  try {
    Response response = getResponseWithInterceptorChain(forWebSocket); // ①
    if (canceled) {
      signalledCallback = true;
      responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
    } else {
      signalledCallback = true;
      responseCallback.onResponse(RealCall.this, response);
    }
  } catch (IOException e) {
    if (signalledCallback) {
      // Do not signal the callback twice!
      Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
    } else {
      responseCallback.onFailure(RealCall.this, e);
    }
  } finally {
    client.dispatcher().finished(this);
  }
}

① 在这里我们有机会通过自己Interceptor 来处理请求和响应, 在Retrofit 中默认定义了一个 ApplicationInterceptorChain,请求从这里开始处理。

 @Override 
 public Response proceed(Request request) throws IOException {
  // If there's another interceptor in the chain, call that.
  if (index < client.interceptors().size()) {
    Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
    Interceptor interceptor = client.interceptors().get(index);
    Response interceptedResponse interceptor.intercept(chain);

    if (interceptedResponse == null) {
      throw new NullPointerException("application interceptor " + interceptor
          + " returned null");
    }
    return interceptedResponse;
  }
  // No more interceptors. Do HTTP.
  return getResponse(request, forWebSocket);
}

这里实际上有一个类似递归的调用,通过不断的 改变 ApplicationInterceptorChain 的 index, 来使每个interceptor的intercept 方法调用,并且通过request 这个引用,来使request 所指向的对象得到每个拦截器的处理。这里拦截器可以想想java Web 中Servlet 中拦截器的处理。

接下来getResponse() 方法 就是真正发送Http请求的地方,这个里面涉及到较多okHttp 的使用,这里就不分析了,等后面看了okhttp 的源码再来说。

在getResponse() 中会得到一个okhttp response 的对象,根据请求的结果来回调 responseCallback 的 onFailure 和 onResponse 方法。

responseCallback 这个对象就是在OkHttpCall 的 enequeue 方法中 调用 RealCall enequeue 方法传入的,那么接下来在回到 OkHttpCall 的 enqueue 方法。

public void enqueue(final Callback<T> callback) {
    ....

    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();
    }
  }
});
}

从这里调用我们可以简单的看出这里实际上又是Callback的一个包装,拿到okhttp3.Response 对象之后调用 parseResponse 方法,将OkHtt Response 转换为一个 Retrofit 的 Response.
然后调用 callSuccess 最终来回调我们使用时传入的callback.

到这里我们使用Retrofit 实现一个异步请求的过程就分析完成了。