读源码-Retrofit源码解析


本文基于Retrofit版本:

com.squareup.retrofit2:retrofit:2.9.0

1-基本流程

Retrofit框架其实可以理解为OkHttp的第一个Interceptor,对OkHttp的请求及结果进行处理,符合RESTful规范的一个框架,同时也支持通过RxJava实现响应式编程,通过一系列的封装使得OkHttp用起来更方便。本文重点解析Retrofit部分原理,至于其核心的OkHttp部分前面的文章已经分析过了:读源码-OkHttp源码解析

1.1-创建Retrofit实例

通过Retrofit实现网络通信,第一步当然是初始化工作了。Retrofit和OkHttp的代码风格很像,同样采用建造者模式构建Retrofit实例:

Retrofit mRetrofit = new Retrofit.Builder()
                    .baseUrl("https://wanandroid.com/")
                    .addConverterFactory(JacksonConverterFactory.create())
                    .build();

逻辑很简单就是通过获取Retrofit的构造器Builder对象,创建Retrofit实例,并初始化一些配置项。我们直接看build方法中初始化了哪些配置项:

public Retrofit build() {
      //baseUrl必须要配置,一般是服务端域名的scheme+host
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      //创建OkHttpClient实例,通过OkHttp处理后续网络请求和响应
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      //回调处理器,默认为null   
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
      //设置网络请求适配器工厂类,默认CompletableFutureCallAdapterFactory
      //可以设置成RxJava3CallAdapterFactory来支持RxJava3
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
      //添加默认数据转换器工厂BuiltInConverters
      converterFactories.add(new BuiltInConverters());
      //添加自定义数据转换器工厂,例如设置JacksonConverterFactory,支持通过Jackson来解析数据
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
      return new Retrofit(。。。//实参省略);
    }
  }

初始化过程中主要涉及到的配置项:

  • baseUrl 必选,标识服务端地址的scheme+host
  • callFactory 默认OkHttpClient,处理网络通信部分
  • callAdapterFactories 默认CompletableFutureCallAdapterFactory,可以将OkHttpCall转换成适合不同平台来调用的网络请求
  • converterFactories 默认BuiltInConverters,数据转换器工厂,BuiltInConverters直接取对应的值并未转换。可以通过设置JacksonConverterFactory来使用Jackson解析json数据,GsonConverterFactory来用Gson解析,如果要用FastJson需要继承Converter.Factory自定义数据转换工厂。

1.2-创建请求接口

创建网络请求接口,通过注解的方式写入要调用接口的url的后半部分,前半部分已在初始化时配置baseUrl。先看代码

public interface AppService {
    //请求方法为GET,path=wxarticle/chapters/json
    @GET("wxarticle/chapters/json")
    Call<TextResponse> getAuthorList();
}

可以看到通过注解标注请求方法类型及请求url的后半部分,定义方法需要设定方法返回参数类型,根据服务端返回的数据格式自定义Data类。接口创建完后,通过Retrofit创建接口实例?对,实例的是继承该接口的代理类,Retrofit通过动态代理该请求接口来实现方法调用。

AppService mService = mRetrofit.create(AppService.class);//生成接口的动态代理对象
Call<TextResponse> call = mService.getAuthorList();//通过代理实现网络请求
接着看Retrofit.create是如何创建并实例化代理对象的。
public <T> T create(final Class<T> service) {
    //@1.验证接口合法性,解析获取接口中的所有注解方法封装成ServiceMethod
    validateServiceInterface(service);
    //通过InvocationHandler实例化动态代理类
    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 {
                // 如果是Object可以访问的方法,直接调用
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                //默认方法,即public非静态方法,正常反射调用
                //@2.非默认方法,获取对应ServiceMethod对象并调用invoke方法
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

@1.验证接口合法性,解析获取接口中的所有注解方法封装成ServiceMethod

private void validateServiceInterface(Class<?> service) {
    if (!service.isInterface()) {//必须是接口
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    //验证接口泛型参数及接口类型
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message =
            new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ").append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }
    //如果设置了预解析,提前解析获取非默认方法列表并缓存,方法会封装成ServiceMethod对象
    //动态代理对象也是通过调用loadServiceMethod来解析非默认方法并调用
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        //非静态默认方法
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

@2.非默认方法,获取对应ServiceMethod对象并调用invoke方法

ServiceMethod<?> loadServiceMethod(Method method) {
    //优先从缓存中获取
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;
    synchronized (serviceMethodCache) {
      //加锁后再次尝试从缓存中获取  
      result = serviceMethodCache.get(method);
      if (result == null) {
        //@3.解析该方法,获取注解信息构建请求Request
        //构建请求对象及Http请求方法最终封装成HttpServiceMethod
        result = ServiceMethod.parseAnnotations(this, method);
        //缓存该方法  
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

@3.parseAnnotations方法中

  • 第一步:解析注解方法中的参数信息,例如1.2中定义的方法getAuthorList,解析后得到调用方法类型GET、请求域名path=wxarticle/chapters/json、响应数据类型TextResponse。根据这些信息创建Http请求Request的工厂类
  • 第二步:将方法信息,Request工厂及Retrofit引用封装到HttpServiceMethod。1.2中的例子调用代理对象的getAuthorList()方法最终是调用了HttpServiceMethod对象的invoke方法来发起网络请求。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //@4.第一步根据注解生成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.");
    }
    //@5.第二步,根据Request工厂类及Retrofit实例引用构建HttpServiceMethod对象,供代理对象调用发起网络请求
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

@4.第一步根据注解生成Request的工厂类。调用链路RequestFactory.parseAnnotations–>RequestFactory.Builder.build

RequestFactory build() {
    //先解析Http 方法 get/post/delete等,对应例子中的GET方法
    for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
    }
    。。。//省略 Http 方法解析异常处理
    
    //解析注解接口的入参,对应例子中的"wxarticle/chapters/json"
    int parameterCount = parameterAnnotationsArray.length;
    parameterHandlers = new ParameterHandler<?>[parameterCount];
    for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
    }
    。。。//省略 Http 请求参数解析异常处理 
        
    //将解析出来的参数生成RequestFactory实例
    return new RequestFactory(this);
}

@5.第二步,根据Request工厂类及Retrofit实例引用构建HttpServiceMethod对象,供代理对象调用发起网络请求。

static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;
    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
        。。。//Kotlin支持
    } else {
        //获取方法类型
        adapterType = method.getGenericReturnType();
    }
    //获取CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    //根据CallAdapter获取response类型,默认Call<T>
    //如果设置为RxJava3CallAdapter则返回Observalbe<T>
    Type responseType = callAdapter.responseType();
    。。。//省略responseType异常校验
    
    //获取response body数据转换器。对应例子中JacksonConverterFactory.responseBodyConverter
    //用于将response 的body转换成用户设置的数据类型
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        //将CallAdapter封装进去
        return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
        。。。//kotlin检测
    } else {
        。。。//kotlin检测
    }
}

1.3-请求及回调处理

前面创建了服务接口的代理对象,发起网络请求时通过代理对象调用HttpServiceMethod.invoke

@Override
final @Nullable ReturnT invoke(Object[] args) {
    //生成OkHttpCall实例
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    //@6.发起请求
    return adapt(call, args);
}

前面1.2最后HttpServiceMethod.parseAnnotations方法返回的是封装了CallAdapter的CallAdapted对象,所以adapt方法是CallAdapted中实现的。调用链路CallAdapted.adapt–>CallAdapter.adapt–>OkHttpCall.enqueue

public void enqueue(final Callback<T> callback) {
    Objects.requireNonNull(callback, "callback == null");
    okhttp3.Call call;
    Throwable failure;
    synchronized (this) {
        if (executed) throw new IllegalStateException("Already executed.");
        executed = true;
        call = rawCall;
        failure = creationFailure;
        if (call == null && failure == null) {
            try {
                //创建OkHttp的Request对象,再封装成OkHttp.call
                //这里用到了1.2章@4处创建的RequestFactory工厂类来创建Request
                call = rawCall = createRawCall();
            } catch (Throwable t) {
                throwIfFatal(t);
                failure = creationFailure = t;
            }
        }
    }
    。。。//省略
    //通过OkHttp发送网络请求
    call.enqueue(
        new okhttp3.Callback() {
            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                Response<T> response;
                try {
                    //@6.解析OkHttp返回结果
                    response = parseResponse(rawResponse);
                } catch (Throwable e) {
                    throwIfFatal(e);
                    callFailure(e);
                    return;
                }
                try {
                    //调用Call.onResponse回调,即最终结果回调
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    throwIfFatal(t);
                    t.printStackTrace(); // TODO this is not great
                }
            }
            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
            }
            。。。//callFailure方法处理失败回调
        });
}

@6.解析OkHttp返回结果。OkHttpCall.parseResponse

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();//获取OkHttp返回结果类型ResponseBody的对象
    //获取响应体部分
    rawResponse =
        rawResponse
        .newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();
    
    int code = rawResponse.code();
    。。。//根据相应状态码处理失败或异常情况
    //创建ResponseBody的代理对象
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
        //通过初始化时设置的数据转换器来将OkHttp的response转换成接口方法的返回类型
        //对应例子中的设置的JacksonResponseBodyConverter.convert方法
        //通过代理对象catchingBody读取数据流转换成TextResponse对象
        //将转换后的结果封装成Retrofit的Response类型返回,调用Call.onResponse回调
        T body = responseConverter.convert(catchingBody);
        return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
        catchingBody.throwIfCaught();
        throw e;
    }
}

2-总结

通过Retrofit的简单实用分析完了其主要流程,内容是不是很少,Retrofit的核心就是其代码中用到的各种设计模式。总结下Retrofit的简单调用流程:

  1. 初始化Retrofit
  2. 创建请求接口Service
  3. 通过动态代理ServiceProxy调用HttpServiceMethod的invoke
  4. 生成OkHttp需要的 Request对象通过OkHttpCall发起网络请求
  5. 返回OkHttp类型的Response,通过Converter转换为返回参数类型T
  6. 回调Call.onResponse
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值