• Retrofit原理解析(一)


    前言

    Retrofit是什么?

    Retrofit是一个restfulHTTP网络请求框架的封装;

    那为什么起名叫Retrofit呢?

    Retrofit翻译为中文,意为改造翻新之意,Retrofit网络请求的本质是交给内部的OkHttp来完成的,自身只负责网络请求接口的封装,这样一想,名字起的真是十级👍;

    我们先简单看下Retrofit工作流程图:

    Retrofit工作流程

    • APP应用端通过Retrofit请求网络,实际上是使用Retrofit接口层封装请求参数,如HeaderUrl等信息,之后交给OkHttp完成后续的请求;
    • 当服务端返回请求数据后,OkHttp将请求原始数据交给Retrofit,Retrofit根据用户需求对结果进行解析;

    因此,网络请求的本质仍然是OkHttp实现的,Retrofit只是帮使用者进行了工作简化,比如配网入参、封装请求、解析数据等工作,提供了这一系列的复用性;

    Retrofit请求原理解析

    在分析Retrofit请求原理之前,我们先看下Retrofit是如何发起网络请求的?

    代码示例

     		// 1.构建retrofit对象
            val retrofit = Retrofit.Builder()
                .baseUrl("https://www.wanandroid.com")
                .addConverterFactory(GsonConverterFactory.create(Gson()))
                .build()
    
            // 2.通过动态代理构造请求Call
            val loginService: ILoginService = retrofit.create(ILoginService::class.java)
            val loginCall = loginService.login("123")
    
            // 3.调用Call发起网络请求
            loginCall.enqueue(object: retrofit2.Callback<User> {
                override fun onResponse(
                    call: retrofit2.Call<User>,
                    response: retrofit2.Response<User>
                ) {
    
                }
    
                override fun onFailure(call: retrofit2.Call<User>, t: Throwable) {
    
                }
    
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    接下来,我们就通过分析源码来看Retrofit是如何通过封装OkHttp从而发起网络请求的;

    Retrofit源码分析

    我们根据上面的使用方式,将整个网络请求分为以下三个主要步骤:

    1. 构建Retrofit对象
    2. 使用动态代理构造请求Call
    3. 通过Call发起网络请求

    接下来,我们就围绕这三个主体步骤进行源码分析;

    构建Retrofit对象

    我们先看下Retrofit.build()源码里都做了什么?

     public Retrofit build() {
     	 //判断baseUrl 不可以为空
         if (baseUrl == null) {
           throw new IllegalStateException("Base URL required.");
         }
         
       // 初始化请求Call,从命名看可能考虑后续拓展命名为工厂,但目前默认只支持OkHttp请求,不支持其他请求方式;
         okhttp3.Call.Factory callFactory = this.callFactory;
         if (callFactory == null) {
           callFactory = new OkHttpClient();
         }
       	// 添加一个线程管理 executor,我们知道okhttp中请求结束后需要手动切换线程,而retrofit不需要,正是因为	      			   callbackExecutor的存在,其实就是一个handler的封装
         Executor callbackExecutor = this.callbackExecutor;
         if (callbackExecutor == null) {
           callbackExecutor = platform.defaultCallbackExecutor();
         }
    
         // 将构建的callbackExecutor包装到callAdapterFactories集合中存储,以便后续使用;
         List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
         // 默认添加 DefaultCallAdapterFactory类
         callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
    
         // 构建转换器并包装到converterFactories集合中存储,这里以便后续使用;
         List<Converter.Factory> converterFactories =
             new ArrayList<>(
                 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
         converterFactories.add(new BuiltInConverters());
         converterFactories.addAll(this.converterFactories);
         converterFactories.addAll(platform.defaultConverterFactories());
    
         return new Retrofit(
             callFactory,
             baseUrl,
             unmodifiableList(converterFactories),
             unmodifiableList(callAdapterFactories),
             callbackExecutor,
             validateEagerly);
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    其中platform.defaultCallbackExecutor具体代码如下:

      static final class Android extends Platform {
        @Override
        public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();
        }
    	...
        static final class MainThreadExecutor implements Executor {
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override
          public void execute(Runnable r) {
            handler.post(r);
          }
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可以看到仅仅是构造了主线程的Handler,用于后续线程切换使用;

    我们再看看默认添加的 platform.defaultCallAdapterFactories(callbackExecutor)

      List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
          @Nullable Executor callbackExecutor) {
        DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
        return hasJava8Types
            ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
            : singletonList(executorFactory);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里就是创建一个DefaultCallAdapterFactory用于后续OkHttp发起网络请求,我们后续再详细分析;

    小结

    Retrofit.build()使用建造者模式,做一些准备工作,主要如下:

    • baseUrl判空
    • 构建OkHttpClient
    • 构建CallAdapterFactory用于后续网络请求
    • 构建ConverterFactory用于后续数据解析
    动态代理构造请求Call

    接下来我们继续分析这两行代码源码:

       // 2.通过动态代理构造请求Call
           val loginService: ILoginService = retrofit.create(ILoginService::class.java)
           val loginCall = loginService.login("123")
    
    • 1
    • 2
    • 3

    其中retrofit.create源码如下:

      public <T> T create(final Class<T> service) {
       validateServiceInterface(service);
       //通过动态代理的方式生成具体的网络请求对象
       return (T)
           Proxy.newProxyInstance(
               service.getClassLoader(),
               new Class<?>[] {service},
               new InvocationHandler() { //统一处理所有的请求方法
                 private final Platform platform = Platform.get();
                 private final Object[] emptyArgs = new Object[0];
    
                 @Override
                 public @Nullable 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);
                   }
                   args = args != null ? args : emptyArgs;
                   // 根据方法生成一个serviceMethod对象【内部会将生成的ServiceMethod进行缓存处理】
                   return platform.isDefaultMethod(method)
                       ? platform.invokeDefaultMethod(method, service, proxy, args)
                       : loadServiceMethod(method).invoke(args);
                 }
               });
     }
       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    其中serviceMethod.invoke(args)代码如下:

     @Override
     final @Nullable ReturnT invoke(Object[] args) {
      // 根据ServiceMethod对象和请求参数生成一个OkHttpCall对象,用于后续调用OkHttp的接口发起网络请求
       Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
       //调用adapt方法,并传入OkHttpCall,内部会进行包装,返回一个Call对象,用于后续网络请求
       return adapt(call, args);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    上述代码流程如下:

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

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

    我们在使用Retrofit的时候,对每一个网络请求的产生都必须先调用create函数,也就是意味着,我们的请求都是通过代理类来处理的,而代理类具体的代理行为是发生在哪里呢?很显然,并不是在create函数执行的时候,而是在使用具体的接口创建具体网络请求Call的时候,也就是对应如下这行代码:

     val loginCall = loginService.login("123")
    
    • 1

    在执行上面代码的时候,它会走代理设计模式中的InvocationHandler.invoke方法,也就是所有的网络请求在创建具体网络请求call的时候,都会走InvocationHandler.invoke方法,而从我们可以在此方法里进行各种行为的统一处理,比如:接口的统一配置,也就是注解的解析和网络请求参数的拼接;

    ServiceMethod

    我们先看看loadServiceMethod方法

    
      private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
    
      ServiceMethod<?> loadServiceMethod(Method method) {
        ServiceMethod<?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = ServiceMethod.parseAnnotations(this, method);
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    loadServiceMethod首先会从缓存中获取ServiceMethod对象,如果没有,再通过parseAnnotations构造一个并缓存起来;

    每一个method都有一个自己的ServiceMethod,也就是说我们定义的网络访问接口类,在接口类里面的每一个函数都会在反射阶段形成自己的servicemethod,那么ServiceMethod里面存放的是什么呢?

    ServiceMethod其实是用来存储一次网络请求的基本信息,比如HostURL请求方法等,同时ServiceMethod还会存储用来适配OkHttpCall对象的CallAdapterServiceMethodparseAnnotations方法会解析传入的method,首先ServiceMethod会在CallAdapterFactory列表中寻找合适的CallAdapter来包装OkHttpCall对象,这一步主要是根据Method的返回参数来匹配的,比如如果方法的返回参数是Call对象,那么ServiceMethod就会使用默认的CallAdapterFactory来生成CallAdapter,而如果返回对象是RxJava的Observable对象,则会使用RxjavaCallAdapterFactory提供的CallAdapter。

    CallAdapter

    我们考虑一下这个问题?为什么InvocationHandler.invoke方法不可以直接返回OKHttpCall对象,而是调用adapt(call, args)进行了适配器适配?

    我们知道Retrofit真正使用OkHttp进行网络请求的就是OkHttpCall这个类;改动后也可以实现网络请求;

    但是改动后的代码带来的后果之一就是:因为OkHttpCall实现了Call接口,API Service方法的返回值必须是Call类型,直观表现如下所示:

    public interface ILoginService {
    
        @GET("user/login")
        Call<User> login(String userId);
    
        @GET("user/register")
        Call<User> register(String userId);
    
        @GET("user/update")
        Call<User> update(String userId);
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    如果没有适配器的时候,我们网络请求返回接口只能直接返回OkHttpCall,那所有的网络请求都是用OkHttpCall进行,这样就失去了Retrofit封装的意义了,比如RxJava的Observable就无法支持了。

    这里适配器模式发挥了作用,将网络请求的核心类OkHttpCall进行适配,你需要什么类型的数据就通过适配器适配,返回适配后的对象,正是这种CallAdapter接口的设计,使用我们在使用Retrofit的时候可以自定义我们想要的返回类型;

    我们可以看下Retrofit默认采用的DefaultCallAdapterFactory中的源码:

    final class DefaultCallAdapterFactory extends Factory {
        static final Factory INSTANCE = new DefaultCallAdapterFactory();
    
        DefaultCallAdapterFactory() {
        }
    
        @Nullable
        public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
            if (getRawType(returnType) != Call.class) {
                return null;
            } else {
                final Type responseType = Utils.getCallResponseType(returnType);
                
                return new CallAdapter<Object, Call<?>>() {
                    public Type responseType() {
                        return responseType;
                    }
    				//将OkHttpCall适配成Call对象并返回,也就是`InvocationHandler.invoke`最终的返回值
                    public Call<Object> adapt(Call<Object> call) {
                        return call;
                    }
                };
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    我们再跟进下ServiceMethod.parseAnnotations方法;

       ### ServiceMethod.parseAnnotations方法
       
      static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
      	//根据method构造Request数据工厂
        RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
    
        Type returnType = method.getGenericReturnType();
        if (Utils.hasUnresolvableType(returnType)) {
          throw methodError(method,
              "Method return type must not include a type variable or wildcard: %s", returnType);
        }
        if (returnType == void.class) {
          throw methodError(method, "Service methods cannot return void.");
        }
    
        return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
      }
    
     ### HttpServiceMethod.parseAnnotations方法
    
      static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
          Retrofit retrofit, Method method, RequestFactory requestFactory) {
          //构造callAdapter,用于OkHttpCall转换
        CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
        Type responseType = callAdapter.responseType();
        if (responseType == Response.class || responseType == okhttp3.Response.class) {
          throw methodError(method, "'"
              + Utils.getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
        }
        if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
          throw methodError(method, "HEAD method must use Void as response type.");
        }
    	//构造Converter,用于数据解析
        Converter<ResponseBody, ResponseT> responseConverter =
            createResponseConverter(retrofit, method, responseType);
    	//默认的OkHttpClient
        okhttp3.Call.Factory callFactory = retrofit.callFactory;
        return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    整体看下来就是构造一个HttpServiceMethod对象,里面存放的内容如下:

    • requestFactory:解析注解构造的请求工厂数据,里面有method,baseUrl,httpMethod等等;
    • callFactory:默认为OkHttpClient对象;
    • callAdapter:用于适配OkHttpCall的适配器;
    • responseConverter:用于解析响应的converter;
    调用OkHttpCall发起网络请求

    通过上面的动态代理方法调用,我们已经构造了具备发起网络请求的Call,接下来就是发起最终的网络请求

          // 3.调用OkHttpCall发起网络请求
            loginCall.enqueue(object: retrofit2.Callback<User> {
                override fun onResponse(
                    call: retrofit2.Call<User>,
                    response: retrofit2.Response<User>
                ) {
    
                }
    
                override fun onFailure(call: retrofit2.Call<User>, t: Throwable) {
    
                }
    
            })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    enqueue源码如下:

    
    	### ExecutorCallAdapterFactory.ExecutorCallbackCall.enqueue()方法
    	
       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) {
          checkNotNull(callback, "callback == null");
    		//delegate是Call类型,最终会调用OkHttpCall.enqueue发起网络请求,这里不在深入;
          delegate.enqueue(new Callback<T>() {
            @Override public void onResponse(Call<T> call, final Response<T> response) {
            	//通过callbackExecutor实现线程切换到主线程!!!
              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);
                }
              });
            }
          });
        }
    
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    这里就比较简单了,不再过多赘述,我们继续看下返回结果是如何通过前面提到的converter进行解析的;

    Converter请求与返回数据转换

    我们主要跟进下 response = parseResponse(rawResponse)这段源码:

     ### OkHttpCall.parseResponse()方法
     
      Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
      	...
        try {
          T body = responseConverter.convert(catchingBody);
          return Response.success(body, rawResponse);
        } catch (RuntimeException e) {
    		...
          throw e;
        }
      }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    responseConverter.convert是接口返回的调用,其实现类如下:
    converter接口实现类
    这里我们重点看下GsonRequestBodyConverter【请求数据转换】和GsonResponseBodyConverter【返回数据转换】

    GsonRequestBodyConverter

    final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
      private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
      private static final Charset UTF_8 = Charset.forName("UTF-8");
    
      private final Gson gson;
      private final TypeAdapter<T> adapter;
    
      GsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
      }
    
      @Override public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    GsonResponseBodyConverter

    final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
      private final Gson gson;
      private final TypeAdapter<T> adapter;
    
      GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
      }
    
      @Override public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
          return adapter.read(jsonReader);
        } finally {
          value.close();
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可以看到最终就是通过Gson的方法调用完成请求与返回数据的转换;

    Retrofit整体网络请求流程图

    Retrofit网络请求流程图

    总结

    Retrofit将设计模式运用到了极致,涉及到的设计模式有动态代理建造者外观模式适配器装饰器等,其中动态代理更是整个网络请求的核心,Retrofit的源码看下来也比较流畅,真是不得不让人佩服!!!

    后面我们继续学习Retrofit中涉及到的设计模式Retrofit原理解析(二)

    结语

    如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

  • 相关阅读:
    react中怎么为props设置默认值
    五、同步计数器及源码
    C# 处理TCP数据的类(服务端)
    games101-1 光栅化与光线追踪中的空间变换
    图计算引擎分析--GridGraph
    移位寄存器使用
    2.C#:lenson2_TextBox
    JS 流行框架(三):Koa2
    大商创的开源代码中有很多后门,以方便官方监控系统的使用,官方做的真是无孔不入啊,我找到了下面几种
    如何成为一名获得 Adobe 国际认证的专业设计师?
  • 原文地址:https://blog.csdn.net/a734474820/article/details/126547364