Retrofit和OkHttp源码分析

1 篇文章 0 订阅
1 篇文章 0 订阅

Retrofit是Square公司开发的一个网络请求相关的库,它的主要是对网络请求做了一系列封装,使得我们的调用比较简单。网络部分默认采用OkHttp。

retrofit-2.1.0.jar

META-INF
retrofit2
http(目录,一些注解的申明)
BuiltInConverters
Call (请求接口)
CallAdapter (Call适配器接口)
Callback (请求结果回调接口)
Converter (请求和响应装换器接口)
DefaultCallAdapterFactory (默认的CallAdapter 工厂)
ExecutorCallAdapterFactory (线程执行器CallAdapter工厂)
OkHttpCall (请求核心类)
ParameterHandler (对请求参数的处理)
Platform (三种平台)
RequestBuilder (请求的构建器)
Response (响应类)
Retrofit (核心)
ServiceMethod (接口调用封装)

Utils (工具类)

从上面结构我们可以看出,整个Retrofit的包结构非常简单。

Retrofit 使用 Builder构建,Retrofit.Builder包含以下几个成员

private Platform platform;
    private okhttp3.Call.Factory callFactory;
    private HttpUrl baseUrl;
    private List<Converter.Factory> converterFactories = new ArrayList<>();
    private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    private Executor callbackExecutor;
    private boolean validateEagerly;

platform:通过Platform.get()获取到一个单例的Platform,Android平台获得默认的Android类实例,此外还有Java8和IOS。

Android的 defaultCallbackExecutor 方法返回一个叫 MainThreadExecutor 的Executor,该Executor是使用主线程的Looper,此外,defaultCallAdapterFactory 返回一个默认的 CallAdapterFactory 工厂(这里是 ExecutorCallAdapterFactory),用来生成一个call,并最终执行callbackExecutor。

callFactory:Call 生成的工厂方法,需要实现 newCall 方法,针对 Request 生成对应的 Call,默认使用 OkHttpClient。我们可以通过 OkHttpClient.Builder 配置 OkHttpClient,如添加缓存,添加拦截器用来记录日志,添加公共参数,加密请求参数等等,当然我们也可以也可以实现自己的CallFactory

baseUrl:接口地址的基地址,我们可以直接提供诸如http://www.xxx.com/,会自动帮我们生成HttpUrl的实例

converterFactories:数据转换器Converter工厂,将请求和响应数据转换到指定数据类型,如ScalarsConverterFactory(普通数据类型转换,如Boolean,Integer,  String等)、GsonConverterFactory(Json数据转成对象)等等,当然我们也可以实现自己的转换器工厂,针对不同的数据类型 将 ResponseBody 转换成我们想要的结果。

adapterFactories:存放CallAdapter工厂,构造时会添加一个默认的platform.defaultCallAdapterFactory(callbackExecutor)用来回调结果

callbackExecutor:回调执行器,默认使用platform.defaultCallbackExecutor

validateEagerly:如果设置true,我们提供的Service会在接口方法执行前就生成所有的ServiceMethod,具体看Retrofit的create方法

build方法源码如下:

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

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        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);
    }

创建Retrofit的实例后,我们调用create方法,为我们创建接口的代理实例(Java的动态代理)

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

当调用定义的接口方法时,会进入上面代理实例的invoke方法。

如果类是Object类型的,将直接调用Object的方法;如果方法是默认方法(default 方法,java8中有效,android默认返回false),将直接调用;否则会生成一个ServiceMethod,同时生成一个OkHttpCall,并调用serviceMethod.callAdapter.adapt方法返回 一个 ExecutorCallbackCall ,当我们调用 call.execute 或 call.enqueue(callback)时,最终会调用 OkHttpCall 的 execute 和 enqueue 方法。

下面我们来看 ServiceMethod 的创建过程:

ServiceMethod.Builder 构造方法传入 retrofit 实例和 method 方法,同时拿到 method 方法的注解、参数类型和参数注解。

build() 方法首先调用 createCallAdapter 创建 callAdapter ,根据 method 的返回类型和参数注解申明,去 retrofit  中注册的 adapterFactories 中查找,并调用 get 方法生成对应的 callAdapter。默认的会调用 ExecutorCallAdapterFactory 的 get 方法返回一个带callback的 ExecutorCallbackCall。然后保存响应数据类型 responseType (如String)。

ExecutorCallAdapterFactory 的 get 方法如下:

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

然后调用 createResponseConverter 创建 responseConverter ,与 callAdapter 的创建过程类似,这里也会从 converterFactories 中查找对应的 converterFactory,例如添加了 ScalarsConverterFactory 后,如果我们最终需要的数据类型是 String , 那么就会返回一个 StringResponseBodyConverter , 它的 convert 方法会将 ResponseBody 转为一个 String 返回。

StringResponseBodyConverter 的声明如下:

static final class StringResponseBodyConverter implements Converter<ResponseBody, String> {
    static final StringResponseBodyConverter INSTANCE = new StringResponseBodyConverter();

    @Override public String convert(ResponseBody value) throws IOException {
      return value.string();
    }
  }

然后是解析 method 的注解和合法性判断。如@GET,@POST等类型注解,还有像@Headers,@FormUrlEncoded等辅助信息

接下来是对于参数声明的解析和一些必要的参数正确性的判断。

最后生成ServiceMethod。

OkHttpCall 实现了 Call 的接口,它持有 ServiceMethod 和 args 即接口方法的入参。

OkHttpCall 主要包含以下几个方法

request() : 该方法返回一个 Request 对象

enqueue(Callback):异步执行方法

execute():同步执行方法

createRawCall():创建一个原始的请求

parseResponse(okHttp3.Response):解析响应结果

createRawCall 中首先调用 serviceMethod 的 toRequest(args)方法生成一个 Request,返回调用 serviceMethod 的 callFactory (即 OkHttpClient) 的 newCall (request) 方法生成一个 Call 即 RealCall。

RealCall 的 execute 方法 调用 client.dispatcher().executed(this); 将自己添加到 OkHttpClient 的 dispatcher 中 的 runningSyncCalls 的队列中,此时call 没有马上执行。然后 getResponseWithInterceptorChain 方法被调用 创建 ApplicationInterceptorChain 并调用 proceed 方法 。

proceed 方法首先调用 OkHttpClient 的 interceptors 拦截器处理请求, 如果没有拦截器,将调用自身的 getResponse 方法获取结果。

getResponse 方法首先对请求做了一些处理,然后创建一个 HttpEngine 的实例 engine,进入 while循环体中。

如果此时任务已被取消,engine 将释放资源并抛出异常。

然后执行 engine.sendRequest 方法 ,源码如下:

public void sendRequest() throws RequestException, RouteException, IOException {
    if (cacheStrategy != null) return; // Already sent.
    if (httpStream != null) throw new IllegalStateException();

    Request request = networkRequest(userRequest);

    InternalCache responseCache = Internal.instance.internalCache(client);
    Response cacheCandidate = responseCache != null
        ? responseCache.get(request)
        : null;

    long now = System.currentTimeMillis();
    cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
    networkRequest = cacheStrategy.networkRequest;
    cacheResponse = cacheStrategy.cacheResponse;

    if (responseCache != null) {
      responseCache.trackResponse(cacheStrategy);
    }

    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

    // If we're forbidden from using the network and the cache is insufficient, fail.
    if (networkRequest == null && cacheResponse == null) {
      userResponse = new Response.Builder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(EMPTY_BODY)
          .sentRequestAtMillis(sentRequestMillis)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
      return;
    }

    // If we don't need the network, we're done.
    if (networkRequest == null) {
      userResponse = cacheResponse.newBuilder()
          .request(userRequest)
          .priorResponse(stripBody(priorResponse))
          .cacheResponse(stripBody(cacheResponse))
          .build();
      userResponse = unzip(userResponse);
      return;
    }

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean success = false;
    try {
      httpStream = connect();
      httpStream.setHttpEngine(this);

      if (writeRequestHeadersEagerly()) {
        long contentLength = OkHeaders.contentLength(request);
        if (bufferRequestBody) {
          if (contentLength > Integer.MAX_VALUE) {
            throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
                + "setChunkedStreamingMode() for requests larger than 2 GiB.");
          }

          if (contentLength != -1) {
            // Buffer a request body of a known length.
            httpStream.writeRequestHeaders(networkRequest);
            requestBodyOut = new RetryableSink((int) contentLength);
          } else {
            // Buffer a request body of an unknown length. Don't write request headers until the
            // entire body is ready; otherwise we can't set the Content-Length header correctly.
            requestBodyOut = new RetryableSink();
          }
        } else {
          httpStream.writeRequestHeaders(networkRequest);
          requestBodyOut = httpStream.createRequestBody(networkRequest, contentLength);
        }
      }
      success = true;
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (!success && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }
  }

sendRequest 首先 对 request 进行一些处理,包括 Host 、Connection、 Accept-Encoding、Cookie、User-Agent等,如果没有设置Accept-Encoding ,OkHttp会自动加上 gzip。接着从 InternalCache 获取缓存的响应结果(这里 Internal.instance 是在 OkHttpClient 中静态语句块中创建的,如果我们设置了缓存,Internal.instance.internalCache(client) 返回 OkHttpClient 的 cache 的一个内部类 InternalCache。当调用InternalCache.get时,最终还是调用了我们 cache 的 get 方法)。然后根据缓存的情况 和请求以及请求的缓存策略,生成一个新的缓存策略(我们可以丢弃一个存在的缓存)。如果支持缓存,记录请求和命中次数;如果缓存存在,但没有响应数据,关闭缓存流。如果没有网络请求并且缓存已失效,将直接返回 504错误;如果没有网络请求,但是有缓存,直接返回该缓存并解压缩

否则,将开始网络请求。

首先 connect 通过 StreamAllocation 返回一个 httpStream ,它主要负责链接管理和数据传输,并将header信息发送出去,然后创建一个 requestBodyOut(类似OutStream)用来发送请求数据。更加请求类型和数据的不同,requestBodyOut的创建方式不同。

请求发送出去后,  engine.readResponse 将被执行,读取网络请求的响应。源码如下:

public void readResponse() throws IOException {
    if (userResponse != null) {
      return; // Already ready.
    }
    if (networkRequest == null && cacheResponse == null) {
      throw new IllegalStateException("call sendRequest() first!");
    }
    if (networkRequest == null) {
      return; // No network response to read.
    }

    Response networkResponse;

    if (forWebSocket) {
      httpStream.writeRequestHeaders(networkRequest);
      networkResponse = readNetworkResponse();
    } else if (!callerWritesRequestBody) {
      networkResponse = new NetworkInterceptorChain(0, networkRequest,
          streamAllocation.connection()).proceed(networkRequest);
    } else {
      // Emit the request body's buffer so that everything is in requestBodyOut.
      if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {
        bufferedRequestBody.emit();
      }

      // Emit the request headers if we haven't yet. We might have just learned the Content-Length.
      if (sentRequestMillis == -1) {
        if (OkHeaders.contentLength(networkRequest) == -1
            && requestBodyOut instanceof RetryableSink) {
          long contentLength = ((RetryableSink) requestBodyOut).contentLength();
          networkRequest = networkRequest.newBuilder()
              .header("Content-Length", Long.toString(contentLength))
              .build();
        }
        httpStream.writeRequestHeaders(networkRequest);
      }

      // Write the request body to the socket.
      if (requestBodyOut != null) {
        if (bufferedRequestBody != null) {
          // This also closes the wrapped requestBodyOut.
          bufferedRequestBody.close();
        } else {
          requestBodyOut.close();
        }
        if (requestBodyOut instanceof RetryableSink) {
          httpStream.writeRequestBody((RetryableSink) requestBodyOut);
        }
      }

      networkResponse = readNetworkResponse();
    }

    receiveHeaders(networkResponse.headers());

    // If we have a cache response too, then we're doing a conditional get.
    if (cacheResponse != null) {
      if (validate(cacheResponse, networkResponse)) {
        userResponse = cacheResponse.newBuilder()
            .request(userRequest)
            .priorResponse(stripBody(priorResponse))
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();
        releaseStreamAllocation();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        InternalCache responseCache = Internal.instance.internalCache(client);
        responseCache.trackConditionalCacheHit();
        responseCache.update(cacheResponse, userResponse);
        userResponse = unzip(userResponse);
        return;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }

    userResponse = networkResponse.newBuilder()
        .request(userRequest)
        .priorResponse(stripBody(priorResponse))
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (hasBody(userResponse)) {
      maybeCache();
      userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
    }
  }

首先是对一些状态的判断,然后根据请求的类型做不同的处理。

1)如果是webSocket,直接写入headers,然后读取响应

2)如果 !callerWritesRequestBody (

true for the {@code HttpURLConnection}-style interaction model
* where control flow is returned to the calling application to write the request body before the
* response body is readable.

从这个注释来看,类似HttpURLConnection类型的请求,需要服务器返回一个控制流后,客户端发送请求体给服务器,然后才能读取响应),将创建一个 NetworkInterceptorChain 并调用 proceed 方法处理请求。

NetworkInterceptorChain 的 proceed 方法中首先也需要 判断是否需要拦截,即是我们在构建OkHttpClient 时添加的networkInterceptors,最后调用 readNetworkResponse 读取响应。

3)否则先发送一次content-length,然后发送请求体,最后读取响应。

上面的三种类型的请求最终都调用 readNetworkResponse 方法返回response。

如果旧的缓存存在,将合并headers并更新缓存,然后返回;否则如果可缓存,缓存response。如果请求失败了,对于不同错误类型,将有可能重新请求。

最后通过dispatcher.finished()方法将自己从同步任务队列中移除。

至此 realCall 的 execute 方法就执行完了,并且返回了一个 Response

OkHttpCall 的 execute 方法中 拿到这个Response,调用 parseResponse 方法解析这个响应。

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      return Response.success(null, rawResponse);
    }

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

首先判断响应状态码是否正确,返回错误的Response 或者 空的Response

然后调用serviceMethod.toResponse  ,最终调用 responseConverter.convert 转化为需要的数据类型,然后返回对应类型的Response。

这样整个请求就完成了。

enqueue 的过程类似,请求过程被封装在一个 AsyncCall 中,最后也是调用 getResponseWithInterceptorChain 获取响应结果并通过Callback回调结果。最后调用 dispatcher.finished时,会执行 promoteCalls 将其他等待的异步任务拉起来。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值