Retrofit2 源码分析

什么是Retrofit

A type-safe HTTP client for Android and Java
一款在Java和Android平台上使用的类型安全的Http客户端

Retrofit的特点

  1. 将API请求转化为接口,具体的接口方法代替各个API
  2. 使用注解标记请求方法类型、参数类型
  3. 支持Multipart和文件上传
  4. 将返回结果转化为对象,并可自定义数据转化器
  5. 提供异步请求方式
  6. 可自定义网络客户端okHttpClient、HttpClient

关键步骤

  1. 请求解析
  2. 请求封装
  3. 请求异步处理
  4. 请求结果转换

    源码分析

关键代码: T create(final Class service) 这个方法包含了上述流程中的请求解析和封装。

public <T> T create(final Class<T> service) {
    //检查接口类的合法性:1、必须是接口类型。2、不能继承其他接口。
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
    //如果需要提前验证接口方法,则走此逻辑。
    //遍历接口中的方法Method,并包装成ServiceMethod,缓存到LinkedHashMap中
      eagerlyValidateMethods(service);
    }
    //使用Java动态代理生成接口具体对象。并封装成ServiceMethod--->OkHttpCall
    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);
            }
            //上面部分可以忽略,如果是Object或平台自带的方法,不进行代理。
            //如果是我们在接口中声明的方法,则构造一个ServiceMethod对象,相当于请求解析。然后根据ServiceMethod和参数构造一个OkHttpCall,相当于请求封装。
            //最后一句,serviceMethod.callAdapter就是Retrofit里面指定的CallAdapter。CallAdapter的作用是将一个请求转化成AdapterFactory要求的返回类型。
            //如果没有自定义返回类型,Retrofit会使用默认的ExecutorCallAdapterFactory
            //Retrofit2执行接口请求时会返回一个Call<T>对象,当调用Call<T>的enqueue或execute方法时,才会真正去请求。
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

1.请求解析
Retrofit的请求解析是通过ServiceMethod这个类完成,将一个接口方法转换成一个HTTP请求。具体的解析过程很繁杂,但是很简单。无非就是取到接口方法的各类注解,然后分别
解析请求类型(parseMethodAnnotation(Annotation anotattion))
解析参数(parseParameter(int p, Type parameterType, Annotation[] annotations))
创建CallAdapter (retrofit.callAdapter(returnType, annotations))
创建ResponseConverter(retrofit.responseBodyConverter(responseType, annotations))

解析完成后,调用ServiceMethod的构造方法new ServiceMethod<>(this);
构造方法如下

ServiceMethod类的构造也是通过Builder模式实现的,下面一一介绍一下ServiceMethod中全局变量的含义。
  ServiceMethod(Builder<T> builder) {
    //Http请求创建工厂,在创建Retrofit对象时指定,类型为okhttp3.Call.Factory,默认的是OkHttpClient
    this.callFactory = builder.retrofit.callFactory();
    //请求适配器,将请求结果转换成指定类型Call<T>
    this.callAdapter = builder.callAdapter;
    //网络请求基础域名地址,可在创建Retrofit对象时指定,也可以通过@URL注解指定
    this.baseUrl = builder.retrofit.baseUrl();
    //请求结果转化器
    this.responseConverter = builder.responseConverter;
    //Http请求类型 String类型,如“GET”/“POST”
    this.httpMethod = builder.httpMethod;
    //接口相对地址
    this.relativeUrl = builder.relativeUrl;
    //请求头信息 Retrofit支持为某个接口单独设置请求头
    this.headers = builder.headers;
    //内容类型即请求头中设置Content-Type的值
    this.contentType = builder.contentType;
    //是否包含请求体,Post和Put请求是由请求体的
    this.hasBody = builder.hasBody;
    //是否使用表单编码格式,当存在@FormUrlEncoded注解,此字段为true
    this.isFormEncoded = builder.isFormEncoded;
    //是否是多部件上传,当存在@MuitlPart注解时,此字段为true
    this.isMultipart = builder.isMultipart;
    //参数注解列表,即由注解指定的参数名称列表。如@Filed("id")
    this.parameterHandlers = builder.parameterHandlers;
  }

除了构造方法,还有两个比较重要的方法 toRequest(Object … args)和toResponse(ResponseBody body)。他们分别使用当前ServiceMethod存储的请求方法信息,生成一个真正的Http请求和自定义解析后的响应。

请求封装

 /** Builds an HTTP request from method arguments. */
  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();
  }

  /** Builds a method return value from an HTTP response body. */
  T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }

请求异步、同步处理
Retrofit2中同步、异步请求是由okHttp3.Call实现的。
异步请求

 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将结果回传给调用者
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });

同步请求

@Override public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      if (creationFailure != null) {
        if (creationFailure instanceof IOException) {
          throw (IOException) creationFailure;
        } else {
          throw (RuntimeException) creationFailure;
        }
      }

      call = rawCall;
      if (call == null) {
        try {
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException e) {
          creationFailure = e;
          throw e;
        }
      }
    }

    if (canceled) {
      call.cancel();
    }

    return parseResponse(call.execute());
  }

请求结果转换
当请求结束后,会调用parseResponse(okhttp3.Response rawResponse)方法

 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 {
    //此处将返回结果交由用户指定或Retrofit默认的Converter进行数据转换。默认的转换器有StreamingResponseBodyConverter、BufferingResponseBodyConverter、ToStringConverter等。
      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;
    }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值