最新retrofit源码解析,腾讯Java开发面试凉凉

最后

小编精心为大家准备了一手资料

以上Java高级架构资料、源码、笔记、视频。Dubbo、Redis、设计模式、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术

【附】架构书籍

  1. BAT面试的20道高频数据库问题解析
  2. Java面试宝典
  3. Netty实战
  4. 算法

BATJ面试要点及Java架构师进阶资料

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

**第一行核心代码解析(ServiceMethod<Object, Object> serviceMethod =

(ServiceMethod<Object, Object>) loadServiceMethod(method)😉**


//获得ServiceMethod,先从ServiceMethodCache中获取,如果缓存中没有,再重新构建,然后再把新获取的缓存到ServiceMethodCache中

  ServiceMethod<?, ?> loadServiceMethod(Method method) {

    ServiceMethod<?, ?> result = serviceMethodCache.get(method);

    if (result != null) return result;



    synchronized (serviceMethodCache) {

      result = serviceMethodCache.get(method);

      if (result == null) {

//如果没有缓存就重新创建一个ServiceMethod实例并缓存

        result = new ServiceMethod.Builder<>(this, method).build();

        serviceMethodCache.put(method, result);

      }

    }

    return result;

  }



下面具体解析:result = new ServiceMethod.Builder<>(this, method).build();

如何通过动态代理把我们定义的网络接口转换为ServiceMethod(实际请求对象)?

下面看看ServiceMethod类,有几个重要的变量,这几个变量包含了我们所有的网络请求的基本信息,它的初始化也是builder模式:


final class ServiceMethod<R, T> {

//OkHttp中的Call

 final okhttp3.Call.Factory callFactory;

//网络请求适配器比如(RxjavaCallAdapter)

  final CallAdapter<R, T> callAdapter;



  private final HttpUrl baseUrl;

//数据转换器(GsonConverterAdapter)

  private final Converter<ResponseBody, R> responseConverter;

//get post delete 等

  private final String httpMethod;

//相对地址(和baseurl拼接在一起)

  private final String relativeUrl;

//请求头

  private final Headers headers;

//body

  private final MediaType contentType;

  private final boolean hasBody;

  private final boolean isFormEncoded;

  private final boolean isMultipart;

//最核心的,方法参数的处理器(方法和方法上面的注解都是它解析的)

  private final ParameterHandler<?>[] parameterHandlers;



一、下面是builder模式内部类,注意3,4,5



    Builder(Retrofit retrofit, Method method) {

//1、retrofit对象

      this.retrofit = retrofit;

//2、请求方法名

      this.method = method;

//3、网络请求接口里面的注解

      this.methodAnnotations = method.getAnnotations();

//4、获取请求接口中参数的类型

      this.parameterTypes = method.getGenericParameterTypes();

//5、获取注解里面的内容

      this.parameterAnnotationsArray = method.getParameterAnnotations();

    }

}



二、build()方法

根据responseType和方法中的注解来解析整个需要的内容

    public ServiceMethod build() {

//1、通过网络请求方法的返回值和注解类型,从retrofit对象中获取请求适配器。

      callAdapter = createCallAdapter(); 

//2、根据网络请求接口方法的返回值和注解类型,从retrofit对象中获取这个请求适配器返回的数据类型

      responseType = callAdapter.responseType();

      if (responseType == Response.class || responseType == okhttp3.Response.class) {

        throw methodError("'"

            + Utils.getRawType(responseType).getName()

            + "' is not a valid response body type. Did you mean ResponseBody?");

      }

//3、创建数据转换器

      responseConverter = createResponseConverter();

//4、遍历注解,解析注解

      for (Annotation annotation : methodAnnotations) {

        parseMethodAnnotation(annotation);

      }

//5、遍历参数,解析参数

      for (int p = 0; p < parameterCount; p++) {

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

      }





总结build()方法:

根据返回值类型和方法中的注解来从网络请求适配器工厂和数据转换器工厂分别获取到(request)请求适配器(callAdapter)和(response) 数据返回转换器(converter);

然后会根据参数注解来获取到参数;最后调用parseParameter解析结果中的参数。



其中里面的方法:




    private CallAdapter<T, R> createCallAdapter() {

//网络接口方法返回的类型

      Type returnType = method.getGenericReturnType();

      if (Utils.hasUnresolvableType(returnType)) {

        throw methodError(

            "Method return type must not include a type variable or wildcard: %s", returnType);

      }

      if (returnType == void.class) {

        throw methodError("Service methods cannot return void.");

      }

//获取网络请求接口里面的注解

      Annotation[] annotations = method.getAnnotations();

      try {

        //returnType:网络请求方法的返回值 ;annotations:注解类型

        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);

      } catch (RuntimeException e) { // Wide exception range because factories are user code.

        throw methodError(e, "Unable to create call adapter for %s", returnType);

      }

    }

调用:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {

    return nextCallAdapter(null, returnType, annotations);

  }

调用:

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,

      Annotation[] annotations) {

    checkNotNull(returnType, "returnType == null");

    checkNotNull(annotations, "annotations == null");



//遍历callAdapter的工厂集合寻找合适的工厂,然后通过get方法来获取CallAdapter,最后赋值给ServiceMethod的callAdapter

    int start = adapterFactories.indexOf(skipPast) + 1;

    for (int i = start, count = adapterFactories.size(); i < count; i++) {

      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);

      if (adapter != null) {

        return adapter;

      }



  }




    private Converter<ResponseBody, T> createResponseConverter() {

//获取接口中注解

      Annotation[] annotations = method.getAnnotations();

      try {

        return retrofit.responseBodyConverter(responseType, annotations);

      } catch (RuntimeException e) { // Wide exception range because factories are user code.

        throw methodError(e, "Unable to create converter for %s", responseType);

      }

    }

调用:

  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {

    return nextResponseBodyConverter(null, type, annotations);

  }

调用:

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(

      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {

    checkNotNull(type, "type == null");

    checkNotNull(annotations, "annotations == null");



//遍历converter的工厂集合寻找合适的工厂,然后通过get方法来获取converter,最后赋值给ServiceMethod的converter

    int start = converterFactories.indexOf(skipPast) + 1;

    for (int i = start, count = converterFactories.size(); i < count; i++) {

      Converter<ResponseBody, ?> converter =

          converterFactories.get(i).responseBodyConverter(type, annotations, this);

      if (converter != null) {

        //noinspection unchecked

        return (Converter<ResponseBody, T>) converter;

      }

    }



  }



第二行核心代码解析OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

OkHttpCall实际调用的是okhttp3.Call rawCall,根据serviceMethod和参数创建Call对象,它就是封装了OkHttp中的Call对象

第三行核心代码解析 return serviceMethod.callAdapter.adapt(okHttpCall);

调用CallAdapter中的adapter方法,将我们Call请求转换成每一个平台所适用的类型。

到此,我们就把creat方法解析完毕了。

那么下面就看看create之后的请求了


        Apis apis = retrofit.create(Apis.class);

        retrofit2.Call<HttpResponse<List<Coin>>> call = apis.getCoinList(null);

        call.enqueue(new retrofit2.Callback<HttpResponse<List<Coin>>>() {

            @Override

            public void onResponse(retrofit2.Call<HttpResponse<List<Coin>>> call, retrofit2.Response<HttpResponse<List<Coin>>> response) {

                

            }



            @Override

            public void onFailure(retrofit2.Call<HttpResponse<List<Coin>>> call, Throwable t) {



            }

        });



同步请求和重要参数

retrofit请求:

retrofit帮我们封装了所有的请求,最终还是交给OkHttp去请求

同步:OkHttpCall.execute()

异步:OkHttpCall.enqueue()

retrofit中具体请求流程:

1、网络接口中的方法和参数利用ParameterHandle来进行解析

2、根据ServiceMethod对象创建一个OkHttp的request对象,有了这个对象才能进行实际的网络请求

(ServiceMethod这个对象很重要,所有需要缓存,它得到后就缓存在ServiceMethodCache中)

3、从ServiceMethod获取到request对象,通过OkHttpCall的底层:OkHttp库发送网络请求

4、通过converter解析数据

一句话总结:

对网络请求接口方法中的每个参数利用ParameterHandle来进行解析,第二步根据我们创建好的ServiceMethod对象创建Request对象,把Request对象交给OkHttp库来进行实际的网络请求发送,发送完后利用数据转换器converter将网络数据转为Java对象。

使用retrofit只需要将焦点放在接口的创建上,通过接口来配置请求即可,它内部的原理就是通过动态代理将接口中的方法转换为ServiceMethod对象,然后通过ServiceMethod对象获取到请求信息,最终网络底层的请求还是交给OkHttp请求的。

在retrofit中:final class OkHttpCall implements Call {},所以call.enqueue或call.execute最终调用的是OkHttpCall中的方法;OkHttpCall中实际使用了:okhttp3.Call

call.enqueue或call.execute最终都会调用createRawCall和parseResponse;

createRawCall得到okhttp3.Call对象,parseResponse解析数据返回

下面具体代码:


  private okhttp3.Call createRawCall() throws IOException {

//调用ParameterHandle解析参数后创建Request对象

    Request request = serviceMethod.toRequest(args);

//创建Call对象

    okhttp3.Call call = serviceMethod.callFactory.newCall(request);

    if (call == null) {

      throw new NullPointerException("Call.Factory returned null.");

    }

    return call;

  }



回顾一下OkHttp库单独使用的步骤:

1、创建OkHttpClient和Request对象

2、将Request封装成Call对象( Call call = client.newCall(request))

3、调用call的enqueue(异步)或execute(同步)发送请求


  Request toRequest(@Nullable Object... args) throws IOException {



    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,

        contentType, hasBody, isFormEncoded, isMultipart);



    //解析注解中的请求入参

    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;



    return requestBuilder.build();

  }




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) {

      rawBody.close();

      return Response.success(null, rawResponse);

    }



    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);

    try {

//将返回的数据通过convert(GsonConvert)转换为Java对象response。

      T body = serviceMethod.toResponse(catchingBody);

//解析完后返回到success方法中

      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;

    }

  }






  R toResponse(ResponseBody body) throws IOException {

    return responseConverter.convert(body);

  }



结语

小编也是很有感触,如果一直都是在中小公司,没有接触过大型的互联网架构设计的话,只靠自己看书去提升可能一辈子都很难达到高级架构师的技术和认知高度。向厉害的人去学习是最有效减少时间摸索、精力浪费的方式。

我们选择的这个行业就一直要持续的学习,又很吃青春饭。

虽然大家可能经常见到说程序员年薪几十万,但这样的人毕竟不是大部份,要么是有名校光环,要么是在阿里华为这样的大企业。年龄一大,更有可能被裁。

送给每一位想学习Java小伙伴,用来提升自己。

在这里插入图片描述

本文到这里就结束了,喜欢的朋友可以帮忙点赞和评论一下,感谢支持!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

toResponse(ResponseBody body) throws IOException {

return responseConverter.convert(body);

}






## 结语

小编也是很有感触,如果一直都是在中小公司,没有接触过大型的互联网架构设计的话,只靠自己看书去提升可能一辈子都很难达到高级架构师的技术和认知高度。向厉害的人去学习是最有效减少时间摸索、精力浪费的方式。

我们选择的这个行业就一直要持续的学习,又很吃青春饭。

虽然大家可能经常见到说程序员年薪几十万,但这样的人毕竟不是大部份,要么是有名校光环,要么是在阿里华为这样的大企业。年龄一大,更有可能被裁。

送给每一位想学习Java小伙伴,用来提升自己。

[外链图片转存中...(img-S96iG8lI-1715647265788)]

> 本文到这里就结束了,喜欢的朋友可以帮忙点赞和评论一下,感谢支持!

> **本文已被[CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)收录**

**[需要这份系统化的资料的朋友,可以点击这里获取](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值