Retrofit原理解析

Retrofit是一个RESful的HTTp网络请求框架的封装

原因是:网络请求的工作本质上是okHttp完成的,而Retrofit仅负责网络请求接口的封装

1.上图说明了啥

1.app应用程序通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,Header,Url等信息,之后由OKHttp完成后续的请求操作

2.在服务器返回数据之后,oktttp将原始的结果交给Retrofit,Retrofit根据用户的需求结果进行分析

在我们看Retrofit的构建过程

Retrofit通过Build模式来生成一个Retrofit对象,通过代码我们知道,Retrofit默认会使用OkHTTP来发送网络请求,当然我们也可以自己定制

    public Retrofit build() {
 

 <--  配置网络请求执行器(callFactory)-->
      okhttp3.Call.Factory callFactory = this.callFactory;
      // 如果没指定,则默认使用okhttp
      // 所以Retrofit默认使用okhttp进行网络请求
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

 <--  配置回调方法执行器(callbackExecutor)-->
      Executor callbackExecutor = this.callbackExecutor;
      // 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor
      // 即Android默认的callbackExecutor
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

 <--  配置网络请求适配器工厂(CallAdapterFactory)-->
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
   
  // 向该集合中添加了步骤2中创建的CallAdapter.Factory请求适配器(添加在集合器末尾)
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
   
// 请求适配器工厂集合存储顺序:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂(ExecutorCallAdapterFactory)

 <--  配置数据转换器工厂:converterFactory -->
      // 在步骤2中已经添加了内置的数据转换器BuiltInConverters()(添加到集合器的首位)
    //中又插入了一个Gson的转换器 - GsonConverterFactory(添加到集合器的首二位)

      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
     
// 数据转换器工厂集合存储的是:默认数据转换器工厂( BuiltInConverters)、自定义1数据转换器工厂(GsonConverterFactory)、自定义2数据转换器工厂....

// 注:
//1. 获取合适的网络请求适配器和数据转换器都是从adapterFactories和converterFactories集合的首位-末位开始遍历
// 因此集合中的工厂位置越靠前就拥有越高的使用权限

      // 最终返回一个Retrofit的对象,并传入上述已经配置好的成员变量
      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

1 :在代码 1 处 (callFactory 网络请求工厂)
初始化 构建 call 的工厂,但是这个地方直接就是使用了 okhttp call ,没有使用到工厂设计模式去添加构建
httpclient 或者 httpurlconnection 的方法来创建 call ,说明 retrofifit 已经铁下心只支持 okhttp 创建 call 请求了。
那么 call 是什么的抽象呢?看下面的代码, okhttp 请求的代码
OkHttpClient http 请求的载体包含 socket 等可以复用的对象,协议配置等等一切。
Request 创建的是一个具体的有 url header ,等请求信息的一个网络请求,表示这个具体的请求。
Call 通往请求的,去执行请求的整个过程的一个抽象。也是进行网络请求的最终接口。
所以,此次调用,目的就是创建了一个 OkHttpClient ,换句话说,这里的调用就是生产 Okhttp 网络请求需要的请
Call 的,以备后面进行真正的网络请求
2 :在代码 2处 (callbackExecutor 回调方法执行器)
网络请求需要在子线程中执行,那么就需要线程管理,所以就有了代码 2 的存在,深入源码后发现,这个地方就是运
handler 进行线程切换,当网络请求回来了进行线程切换,可以看下面的源码
所以,此次调用,目的是构建一个用 handler 封装的 Executor ,以备后面进行网络请求成功后的线程切换用
  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}
3 :在代码 3处( CallAdapterFactory网络请求适配器工厂的集合
在此添加的 CallAdapterFactory 属于系统默认的,当然,我们可以添 RxJavaCallAdapterFactory 。默认的 CallAdapterFactory是 ExecutorCallAdapterFactory 类的对象,在Platform.java Class里面可以梳理出来
所以构建的 Retrofit 都是用于进行后面请求的需要的内容的一个准备工作。也就是封装 Okhttp 需要的准备工作。
4.  converterFactories(数据转换器工厂的集合)
// 将上面创建的GsonConverterFactory放入到 converterFactories数组
// 在第二步放入一个内置的数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
  public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }

<-- 步骤3:在MainActivity创建接口类实例  -->
AccessApi NetService = retrofit.create(NetService.class);

<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象  --> 
        Call<JavaBean> call = NetService.getCall();

这是GsonConverterFactory的类的创建过程

public final class GsonConverterFactory extends Converter.Factory {
  /**
   * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
   * decoding from JSON (when no charset is specified by a header) will use UTF-8.
   */
  public static GsonConverterFactory create() {
    return create(new Gson());
  }

  /**
   * Create an instance using {@code gson} for conversion. Encoding to JSON and
   * decoding from JSON (when no charset is specified by a header) will use UTF-8.
   */
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

Retrofifit 构建 IxxxService 对象的过程
Retrofifit.create()
动态代理的原理主要是在运行时动态生成代理类,然后根据代理类生成一个代理对象,在这个代理对象的方法中中又
会调用 InvocationHandler invoke 来转发对方法的处理。
那么大家一定要关注一个细节,我们在使用 retrofit 的时候,对每一个网络请求的产生都必须要先调用 create 函数,也
就是意味着,我们的请求都是通过代理类来进行处理的。但是代理类具体的代理行为是发生在哪里呢?很显然,他并
不是在 create 函数执行的时候,而是在使用具体的接口创建具体网络请求 Call 的时候,当调用具体网络请求 Call 的代
码示例如下:

 @SuppressWarnings("unchecked")

// Single-interface proxy creation guarded by parameter safety.
  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, @Nullable 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放入到缓存中)
           //如果已经生成过了,就从缓存中获取

 
           ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
          
           
 //根据ServiceMethod对象和请求参数生成一个OkHttpCall对象,这个okHttpCall能够
            //调用okHttp的接口发起网络请求

            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);


           // 调用serviceMethod的callAdapter的adapt方法,并传入okHttpCall,返回一个对象,
          //这个的目的主要是为了适配返回类型,其内部会对OkhttpCall对象进行包装

            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

(1).Retrofit的create方法通过动态代理的模式,生成了实现了具体的网络请求接口的对象,并在InvocationHandler
的invoke方法中统一处理网络请求接口实体对象的方法;
(2).invoke方法会通过方法构造一个ServiceMethod对象,
并将其放入缓存中;
(3)然后根据ServiceMethod对象和网络请求的参数args去构造一个OkHttpCall对象;
(4)最后调用serviceMethod的callAdapter的adapt方法,传入将OkHttpCall对象,callAdapter的目的主要是为了适配
OkHttpCall对象,其内部会对OkHttpCall对象进行包装,生成对应返回类型的对象。

动态代理的原理主要是在运行时动态生成代理类,然后根据代理类生成一个代理对象,在这个代理对象的方法中中又
会调用InvocationHandler的invoke来转发对方法的处理。
下面是MethodService

  // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

//网络请求工厂    就是okHttp的网络请求
  private final okhttp3.Call.Factory callFactory;
 //网络请求适配器  把call请求适配各个平台
  private final CallAdapter<R, T> callAdapter;
//网络基地址
  private final HttpUrl baseUrl;

//数据转换器
  private final Converter<ResponseBody, R> responseConverter;
//网络请求的http方法  比如get  post方法
  private final String httpMethod;
 //网络请求的相对地址  和baseUrl拼接起来就是实际地址
  private final String relativeUrl;

//请求头
  private final Headers headers;
//网络请求的http报文的type
  private final MediaType contentType;

//三个标志位
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;

//方法参数的处理器   比如我们定义的方法  上面的@get和后面的参数
  private final ParameterHandler<?>[] parameterHandlers;

//可以看出是传递的是一个Builder内部类  所以ServiceMethod也是通过构建者模式来初始化他的成员变量的
  ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }


    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method; //网络请求方法
      //获取网络请求方法中的注解 @GET  @POST
      this.methodAnnotations = method.getAnnotations();
      //获取网络请求方法中的参数类型
      this.parameterTypes = method.getGenericParameterTypes();
      //获取网络请求中的注解内容
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

通过Builder方法就能配置我们serviceMethod方法的成员变量

public ServiceMethod build() {
//创建callAdapter
      callAdapter = createCallAdapter();
//  根据网络请求接口返回值类型和注解类型从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?");
      }


//设置请求的数据适配器converter
      responseConverter = createResponseConverter();
// 解读方法的注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

   //获取参数注解的长度
      int parameterCount = parameterAnnotationsArray.length;
    //参数解析器初始化
      parameterHandlers = new ParameterHandler<?>[parameterCount];

      //开始循环解析我们想要的数据类型
       for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {
         Type parameterType = parameterTypes[p];
        //然后通过parseParameter()这个方法来解析参数  通过我们传入的参数类型和参数的注解内容
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);

          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }

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

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }


所以总结的来说就是build方法就是根据我们定义好的请求接口中的返回值类型和方法中的注解来从
我们的网络请求适配器工厂和数据转换器工厂集合中分别获取到我们所需要的网络请求适配器和response数据转换器,
然后根据参数注解去获取到我们所需要的解析的参数,最后调用parseParameter()方法来解析我们接口中的参数


//是根据retrofit网络请求中接口的方法的返回值类型和注解的类型从我们的retrofit对象当中获取对应的网络请求适配器
 private CallAdapter<T, R> createCallAdapter() {
 //获取网络请求接口中方法中的返回值类型
      Type returnType = method.getGenericReturnType();
      。。。。
      //获取注解类型
      Annotation[] annotations = method.getAnnotations();
      //最终调用retrofit的callAdapter  返回我们的网络适配器
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      }
    }


      public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }


   public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {

    int start = adapterFactories.indexOf(skipPast) + 1;
    //创建callAdapter  遍历这个callAdapter的工厂集合  寻找合适的工厂
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
    //然后通过这个工厂的get方法  还有传入的返回值类型和注解类型  创建我们需要的callAdapter  比如RxJavaCallAdapterFactory
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

Retrofifit网络请求操作小结

一般的 Retrofifit 网络请求的操作是指 Call.excute() & Call.enqueue() 的过程,这个过程才是真正的网络请求,因为,
网络配置,请求地址配置, Call 适配,网络请求 requestBody & 返回值 responseBody 转化适配准备工作都已经完
成。
sharedListCall是创建Retrofit的实列化的引用
sharedListCall . enqueue ( new Callback ()...);
sharedListCall . excute ();
1.okHttpCall进行网络请求,实际上是进行okHttp的网络请求
2.利用converter进行网络请求数据的转换一般是gson
3.利用rxjava observable构建Rxjava类型的责任链访问方案,并进行线程切换
4.如果没有添加Rxjava,那么就使用默认的callAdapter里面的callbackExecutor进行线程切换,进行网络请求

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值