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

            }

        })

接下来,我们就通过分析源码来看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);
   }

其中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);
      }
    }
  }

可以看到仅仅是构造了主线程的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);
  }

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

小结

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

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

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

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

其中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);
             }
           });
 }
   

其中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);
 }

上述代码流程如下:

  • 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")

在执行上面代码的时候,它会走代理设计模式中的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;
  }

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<T>类型,直观表现如下所示:

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

如果没有适配器的时候,我们网络请求返回接口只能直接返回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;
                }
            };
        }
    }
}

我们再跟进下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);
  }

整体看下来就是构造一个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) {

            }

        })

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

  }

这里就比较简单了,不再过多赘述,我们继续看下返回结果是如何通过前面提到的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;
    }
  }

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

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

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

Retrofit整体网络请求流程图

Retrofit网络请求流程图

总结

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

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

结语

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值