Retrofit源码解析

news2024/11/14 17:14:17

整体概述

这个是我看完Retrofit的源码后,站在一个高的维度俯瞰整个Retrofit的架构得到的结论。
Retrofit的出现就是对OKHttp做了一个二次封装,为什么要封装?我认为核心目的就是让使用更加的方便。都对哪里进行了封装?

  • 封装了请求参数。改为使用注解的形式,使使用更加的方便,RESTful风格可读性更强。
  • 封装了请求过程。OKHttp中我们需要自己执行请求和回调,这个过程Retrofit帮我们封装了。
  • 封装了结果的处理。这里分两个部分
    • 数据解析
    • 回调内容

可以说Retrofit通过对以上部分的封装,使得开发者只需关心参数,接口,结果即可,中间环节都不需要关心。

阅读思维导图

在这里插入图片描述

基本使用

下面例子来自Retrofit官网https://square.github.io/retrofit/

定义接口
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
使用Retrofit生成service
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);
执行请求
Call<List<Repo>> repos = service.listRepos("octocat");

上面就是一个最简单的使用例子,我们自己项目中一般都做了更加复杂的封装。不过万变不离其宗,上面的例子才是最基础最原始的使用,其他也是基于此改造的。

架构设计

下图摘自 Stay大佬的Retrofit 分析 - 漂亮的解耦套路
这个图绘制的非常清晰,对照着这个图看Retrofit 源码,执行流程等会更加清晰。
在这里插入图片描述

源码分析

备注:本次源码分析基于2.9.0

首先看接口相关的。上面例子中定义了一个GitHubService的接口,里面一个方法listRepos()方法,上面有注解,我们看下Retrofit注解相关的内容

注解

关于注解的代码都在【package retrofit2.http; 】这个包下。
修饰方法的注解有:GET,POST,PUT,DELETE。。。
修饰参数的注解有:Field,Path,Header,Query,Body。。。
这些注解都是Retrofit库提供给我们实现网络请求的,既然是注解就有读取这些注解的地方,这个后面会看到。

修饰请求方法
@Documented
//表示此注解是修饰方法
@Target(METHOD)
//表示此注解运行时候也存在
@Retention(RUNTIME)
public @interface POST {
  /**
   * A relative or absolute path, or full URL of the endpoint. This value is optional if the first
   * parameter of the method is annotated with {@link Url @Url}.
   *
   * <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
   * this is resolved against a base URL to create the full endpoint URL.
   */
  String value() default "";
}
修饰请求参数举例
@Documented
//表示此注解是修饰方法
@Target(PARAMETER)
//表示此注解运行时候也存在
@Retention(RUNTIME)
public @interface Field {
  String value();

  /** Specifies whether the {@linkplain #value() name} and value are already URL encoded. */
  boolean encoded() default false;
}

外观类Retrofit

Retrofit.java的类代码不长,仅仅600多行。首先看构造方法和主要的成员变量。

private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

//这个是OKHttp里面的Call的工厂类
final okhttp3.Call.Factory callFactory;
//OKHttp中封装的一个表示url的类
final HttpUrl baseUrl;
//Converter.Factory的集合
final List<Converter.Factory> converterFactories;
//CallAdapter.Factory的集合
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;

Retrofit(
    okhttp3.Call.Factory callFactory,
    HttpUrl baseUrl,
    List<Converter.Factory> converterFactories,
    List<CallAdapter.Factory> callAdapterFactories,
    @Nullable Executor callbackExecutor,
    boolean validateEagerly) {
  this.callFactory = callFactory;
  this.baseUrl = baseUrl;
  this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
  this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
  this.callbackExecutor = callbackExecutor;
  this.validateEagerly = validateEagerly;
}

//build()方法,主要是暴露给外部调用构造Retrofit的
//这里使用了建造者模式
public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }
  //build建造的时候设置
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
   //build建造的时候没有设置的话,这里new一个新的
    callFactory = new OkHttpClient();
  }

  //build建造的时候设置
  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == null) {
    //build建造的时候没有设置的话,这里使用默认的
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  //可以看出,下面几行代码主要是设置构建converterFactories,
  //并把构建好的converterFactories传递给构造方法中
  // Make a defensive copy of the converters.
  //创建一个预设大小的List
  List<Converter.Factory> converterFactories =
      new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

  // Add the built-in converter factory first. This prevents overriding its behavior but also
  // ensures correct behavior when using converters that consume all types.
  //添加内置的BuiltInConverters
  converterFactories.add(new BuiltInConverters());
  //添加用户自定义的converterFactories
  converterFactories.addAll(this.converterFactories);
  //添加库提供的默认的converterFactories
  converterFactories.addAll(platform.defaultConverterFactories());
  //通过构造方法构建一个Retrofit
  return new Retrofit(
      callFactory,
      baseUrl,
      //Collections的静态方法unmodifiableList得到一个不可变的,不可修改的List。
      unmodifiableList(converterFactories),
      //Collections的静态方法unmodifiableList得到一个不可变的,不可修改的List。
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);
}

通过上面的demo我们看出,这里通过建造者模式构建了一个Retrofit实例。Retrofit是对外的一个外观类,也就是使用了外观模式。构造方法看完了,也创建了Retrofit实例,紧接着我们看看上面例子中retrofit.create(GitHubService.class)这行代码。

public <T> T create(final Class<T> service) {
  //首先校验这个ServiceInterface
  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;
              //排除默认方法,什么是默认方法,Java 8 引入了新的语言特性,就是接口中定义的非抽象非静态的方法
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  //最终核心执行的是这行代码,loadServiceMethod(method)
                  //得到一个ServiceMethod,然后执行ServiceMethod的invoke方法
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

这里做一些校验工作

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());
  }
  //上面例子中并没有设置这个参数,先忽略
  if (validateEagerly) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
      }
    }
  }
}

总结:service的创建是走的代理模式。而执行请求的地方是在代理方法里面。就是上面的invoke方法里面的内容,最终会执行到loadServiceMethod(method).invoke(args)方法。

public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                throws Throwable {
                ...
}

loadServiceMethod

接着先分析loadServiceMethod方法,最终看执行invoke(args)的地方。这里先说关于invoke的结论:ServiceMethod是一个抽象类,invoke并没有实现,实现的地方在子类HttpServiceMethod中。然后再说loadServiceMethod,loadServiceMethod方法是获取一个ServiceMethod,会先调用ServiceMethod.parseAnnotations,然后调用HttpServiceMethod的parseAnnotations方法,最终生成一个ServiceMethod的实例。构建ServiceMethod实例的同时,也将CallAdapter,Converter等准备完成。

//Retrofit.java
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 = ServiceMethod.parseAnnotations(this, method);
      //拿到后写入缓存
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
//ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  //这里构造出一个RequestFactory 
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  //拿到返回类型
  Type returnType = method.getGenericReturnType();
  ...
  //不允许返回空类型
  if (returnType == void.class) {
    throw methodError(method, "Service methods cannot return void.");
  }
  //调用HttpServiceMethod的解析注解方法,传入retrofit,方法,请求参数
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}

这个RequestFactory 里面做了大量的准备工作,主要是将我们给方法和参数写的注解读取出来。包括请求类型,请求header,请求body,path参数等等。

//RequestFactory.java
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
  return new Builder(retrofit, method).build();
}


RequestFactory build() {
  for (Annotation annotation : methodAnnotations) {
  	//解析方法注解
    parseMethodAnnotation(annotation);
  }
  ...
  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);
  }
  ...
  return new RequestFactory(this);
}

//解析方法中的注解,就是前面定义的各种注解,这里不在深入看了,
//只需要知道这里根据注解拿到对应参数即可
private void parseMethodAnnotation(Annotation annotation) {
  if (annotation instanceof DELETE) {
    parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
  } else if (annotation instanceof GET) {
    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
  } else if (annotation instanceof HEAD) {
    parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
  ...
  } else if (annotation instanceof retrofit2.http.Headers) {
    String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
    if (headersToParse.length == 0) {
      throw methodError(method, "@Headers annotation is empty.");
    }
    headers = parseHeaders(headersToParse);
  
    ...
  }
}

HttpServiceMethod.parseAnnotations

//HttpServiceMethod.java
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协程挂起函数,这里先不分析Kotlin相关的
    ...
  } else {
  	//得到返回类型
    adapterType = method.getGenericReturnType();
  }
  
  //创建CallAdapter
  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);
  ...
  
  //创建Converter
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  //是否是Kotlin协程挂起函数,这里不是,所以返回的是CallAdapted
  if (!isKotlinSuspendFunction) {
    return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
  } else if (continuationWantsResponse) {
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForResponse<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
  } else {
    //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForBody<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
            continuationBodyNullable);
  }
}

这个是核心方法,主要有三点:

  • 创建CallAdapter
  • 创建Converter
  • 根据配置或者前面的参数判断构建哪个HttpServiceMethod
    • CallAdapted 主要用于非处理Kotlin协程相关的请求,也就是我们常规的请求
    • SuspendForResponse 处理Kotlin协程相关的请求
    • SuspendForBody
      下面我们分开来看这三点。

创建CallAdapter

//HttpServiceMethod.java
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
    Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
  try {
    //noinspection unchecked
    return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(method, 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) {
  Objects.requireNonNull(returnType, "returnType == null");
  Objects.requireNonNull(annotations, "annotations == null");
  //根据skipPast得到开始查找的角标
  int start = callAdapterFactories.indexOf(skipPast) + 1;
  //循环在callAdapterFactories中查找符合returnType和annotations的CallAdapter.Factory
  //然后CallAdapter.Factory会返回一个CallAdapter,这个是在后面的分析
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    //找到对应的CallAdapter.Factory,然后执行get方法
    CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }

  ...
  //没找到抛出异常
  throw new IllegalArgumentException(builder.toString());
}

关于CallAdapter.Factory,还记得我们上面在分析Retrofit构建的时候有一个CallAdapter.Factory,在例子中我们并没设置CallAdapter.Factory,其实CallAdapter.Factory是用来生成CallAdapter,而CallAdapter又是根据(Type returnType)这个参数来决定的。

public Retrofit build() {
  ...

  // Make a defensive copy of the adapters and add the default Call adapter.
  List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
  //上面官方例子中没有添加callAdapterFactories,所以是空的,
  //所以仅仅添加了platform.defaultCallAdapterFactories(callbackExecutor)
  
  callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

  ...
  
  return new Retrofit(
      callFactory,
      baseUrl,
      unmodifiableList(converterFactories),
      unmodifiableList(callAdapterFactories),
      callbackExecutor,
      validateEagerly);
}

这里还有一个细节,我们自定义的callAdapterFactories在前面,Retrofit提供的默认的defaultCallAdapterFactories在后面,也就是优先去找我们后来自己添加的。
下面看defaultCallAdapterFactories方法

//Platform.java
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
    @Nullable Executor callbackExecutor) {
  DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
  //如果是Java8添加一个CompletableFutureCallAdapterFactory.INSTANCE,
  //否则的话, 只有一个DefaultCallAdapterFactory
  //这里hasJava8Types为true,原因可以自行去看findPlatform方法
  return hasJava8Types
      ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
      : singletonList(executorFactory);
}

接着去看DefaultCallAdapterFactory,上面nextCallAdapter方法会执行到这个get方法,最终是返回一个CallAdapter,例子中returntype为Call<List>,所以会走DefaultCallAdapterFactory的创建CallAdapter的过程。

public @Nullable CallAdapter<?, ?> get(
    Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != Call.class) {
    return null;
  }
  ...

  final Executor executor =
      Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
          ? null
          : callbackExecutor;
  //这里是创建了一个CallAdapter
  return new CallAdapter<Object, Call<?>>() {
    @Override
    public Type responseType() {
      return responseType;
    }

    @Override
    public Call<Object> adapt(Call<Object> call) {
        //这里是核心方法,因为最终会调用到这里
      return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
    }
  };
}

创建Converter

还是回到HttpServiceMethod的parseAnnotations方法

//HttpServiceMethod.java
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();
  
  ...
  
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);
  ..
}


private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
    Retrofit retrofit, Method method, Type responseType) {
  Annotation[] annotations = method.getAnnotations();
  try {
    //跟callAdapter类似,调用retrofit的方法
    return retrofit.responseBodyConverter(responseType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(method, e, "Unable to create converter for %s", responseType);
  }
}
//Retrofit.java
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
  return nextResponseBodyConverter(null, type, annotations);
}

//可以看到跟callAdapter类似,又是去converterFactories这个List里面找对应type, annotations的Converter
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
    @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
  Objects.requireNonNull(type, "type == null");
  Objects.requireNonNull(annotations, "annotations == null");

  int start = converterFactories.indexOf(skipPast) + 1;
  for (int i = start, count = converterFactories.size(); i < count; i++) {
      //找到能够处理当前type, annotations的Converter并返回
    Converter<ResponseBody, ?> converter =
        converterFactories.get(i).responseBodyConverter(type, annotations, this);
    if (converter != null) {
      //noinspection unchecked
      return (Converter<ResponseBody, T>) converter;
    }
  }
  //省略部分异常处理
  ...
  throw new IllegalArgumentException(builder.toString());
}

这次还是回到Retrofit建造者方法中,也就是构建Retrofit的必经之路,看下converterFactories的添加,这里添加了一个BuiltInConverters,然后添加用户自己设置的converterFactories,然后添加platform.defaultConverterFactories(),例子中虽然没添加,但是我们一般情况下都会添加一个GsonConverterFactory

返回CallAdapted

通过上面的分析这里并没有用Kotlin挂起函数,所以isKotlinSuspendFunction为false,返回一个CallAdapted,CallAdapted是HttpServiceMethod的子类,并且是final的静态内部类。现在我们可以在回到loadServiceMethod小结讲的loadServiceMethod(method).invoke(args)方法,最终调用到了HttpServiceMethod,而invoke又调用了adapt方法,最终调用到了子类CallAdapted中的adapt方法,最终调用了CallAdapter的adapt方法

//HttpServiceMethod.java
final @Nullable ReturnT invoke(Object[] args) {
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  return adapt(call, args);
}

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  private final CallAdapter<ResponseT, ReturnT> callAdapter;

  CallAdapted(
      RequestFactory requestFactory,
      okhttp3.Call.Factory callFactory,
      Converter<ResponseBody, ResponseT> responseConverter,
      CallAdapter<ResponseT, ReturnT> callAdapter) {
    super(requestFactory, callFactory, responseConverter);
    this.callAdapter = callAdapter;
  }

  @Override
  protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

上面分析完callAdapter执行的流程了,那么Converter在哪里执行呢?答案是在OkHttpCall中,看HttpServiceMethod.invoke方法中构造了一个OkHttpCall,我们很容易联想到,这个OkHttpCall是不是用来做OKHttp请求的,接着去看下

OkHttpCall

OkHttpCall(
    RequestFactory requestFactory,
    Object[] args,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, T> responseConverter) {
  //请求路径,参数相关
  this.requestFactory = requestFactory;
  this.args = args;
  //okhttp3的请求工厂
  this.callFactory = callFactory;
  //Converter
  this.responseConverter = responseConverter;
}

public Response<T> execute() throws IOException {
  okhttp3.Call call;

  synchronized (this) {
    if (executed) throw new IllegalStateException("Already executed.");
    executed = true;

    call = getRawCall();
  }

  if (canceled) {
    call.cancel();
  }
  //解析结果
  return parseResponse(call.execute());
}

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();
  //一些异常和特殊case处理
  ...

  ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
  try {
    //执行
    T body = responseConverter.convert(catchingBody);
    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;
  }
}

看完OkHttpCall代码就是象我们想的那样,这里是真正执行OkHttp请求的地方,将前面准备好的参数和请求工厂,responseConverter传进来。异常直接返回,成功的话走responseConverter的convert转换数据。

用到的设计模式

简单的如外观模式,单例模式,建造者模式,观察者模式就不再细诉了。
动态代理:每个Service的构建都是通过动态代理实现的,可以说这个动态代理是Retrofit的核心入口,不光包含了请求参数的解析,好包含了CallAdapter,Converter的选择与构建。真正做到了按配置生成。
工厂方法模式:
创建CallAdapter使用了工厂方法模式
抽象工厂模式:
创建Converter对象使用了抽象工厂模式
适配器模式:
将某个类的接口转化为客户端期望的另一个接口表示,主要的目的是兼容性,让原本不匹配不能一起工作的两个类可以协同工作。使用到的CallAdapter就是用了适配器模式。
装饰器模式:
OkHttpCall对Call进行了装饰增强。

参考链接

https://github.com/square/retrofit
https://juejin.cn/post/6844903429811208199
https://www.jianshu.com/p/63b98f6f5301

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1645718.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从一到无穷大 #25 DataFusion:可嵌入,可扩展的模块化工业级计算引擎实现

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言架构总览与可扩展性Catalog and Data SourcesFront End逻辑计划与逻辑计划优化器…

c3 笔记6 认识css样式表

<link>与import应该如何选择?事实上&#xff0c;使用link与import链接外部样式文件的效果看起来是一样的&#xff0c;区别在于<link>是HTML标记而import属于CSS语法。<link>标记有rel、type与href属性&#xff0c;可以指定CSS样式表的名称&#xff0c;这样就…

深度学习之DCGAN

目录 须知 转置卷积 DCGAN 什么是DCGAN 生成器代码 判别器代码 补充知识 LeakyReLU&#xff08;x&#xff09; torch.nn.Dropout torch.nn.Dropout2d DCGAN完整代码 运行结果 图形显示 须知 在讲解DCGAN之前我们首先要了解转置卷积和GAN 关于GAN在这片博客中已经很…

攻防世界-NewsCenter

题目信息 分析过程 题目打开是有个输入框可以用来输入搜索信息&#xff0c;初步判断是个sql注入的题目。接下来判断能否进行sql注入&#xff1a; 输入 hi&#xff0c;有搜索结果&#xff0c;如下图: 输入hi’,无结果&#xff0c;如下图&#xff1a; 初步判定是hi‘后面还有单引…

【Axure高保真原型】动态伸缩信息架构图

今天和大家分享动态伸缩信息架构图的原型模板&#xff0c;我们可以通过点击加减按钮来展开或收起子内容&#xff0c;具体效果可以点击下方视频观看或者打开预览地址来体验 【原型效果】 【Axure高保真原型】动态伸缩信息架构图 【原型预览含下载地址】 https://axhub.im/ax9/…

Python批量修改图片文件名中的指定名称

批量处理图像时&#xff0c;图片名有时需要统一&#xff0c;本教程仅针对图片中名如&#xff1a;0001x4.png&#xff0c;批量将图片名中的x4去除&#xff0c;只留下0001.png的情况。 如果想要按照原图片顺序批量修改图片名&#xff0c;参考其它博文&#xff1a;按照原顺序批量…

SpringBoot整合rabbitmq使用案例

RocketMQ&#xff08;二十四&#xff09;整合SpringBoot SpringBoot整合rabbitmq使用案例 一 SpringBoot整合RocketMQ实现消息发送和接收消息生产者1&#xff09;添加依赖2&#xff09;配置文件3&#xff09;启动类4&#xff09;测试类 消息消费者1&#xff09;添加依赖2&…

Sy9-dhcp/dns服务配置

前言、 课程需要&#xff08;进入服务器综合配置使用阶段了&#xff09;&#xff0c;这里还是沿用桌面版的ubuntu来配置dhcp和dns&#xff0c;这里updated了新的版本。2024.5 server端环境&#xff1a; Win11VMS&#xff1a;192.168.105.1192.168.105.128 &#xff08;ubuntu…

AI热潮开始退去,财务压力迫使多家硅谷明星初创公司选择退出

曾风光无限的Stability AI已重组并削减业务规模&#xff0c;Inflection AI更是关闭业务并基本并入微软。 5月4日消息&#xff0c;国外媒体日前撰文指出&#xff0c;人工智能的热潮已开始逐渐褪去。初创公司想要同微软、谷歌等科技巨头在人工智能领域一决高下&#xff0c;门槛已…

Spring IoCDI(2)—IoC详解

目录 一、IoC详解 1、Bean的存储 &#xff08;1&#xff09;Controller&#xff08;控制器存储&#xff09; 获取bean对象的其他方式 Bean 命名约定 &#xff08;2&#xff09;Service&#xff08;服务存储&#xff09; &#xff08;3&#xff09;Repository&#xff08…

SPA模式下的多页面跳转原理及实现——jQuery Mobile为例

jQuery Mobile在SPA模式下的多页面跳转原理及实现案例 文章目录 jQuery Mobile在SPA模式下的多页面跳转原理及实现案例前言一、SPA的实现原理和代码分析1.实现原理说明&#xff08;1&#xff09;index.html&#xff08;2&#xff09;index.js&#xff08;3&#xff09;page2.ht…

kafka日志存储

前言 kafka的主题(topic)可以对应多个分区(partition)&#xff0c;而每个分区(partition)可以有多个副本(replica)&#xff0c;我们提生产工单创建topic的时候也是要预设这些参数的。但是它究竟是如何存储的呢&#xff1f;我们在使用kafka发送消息时&#xff0c;实际表现是提交…

一款开源高性能AI应用框架

前言 LobeChat 是一个基于 Next.js 框架构建的 AI 会话应用&#xff0c;旨在提供一个 AI 生产力平台&#xff0c;使用户能够与 AI 进行自然语言交互。 LobeChat应用架构 LobeChat 的整体架构由前端、EdgeRuntime API、Agents 市场、插件市场和独立插件组成。这些组件相互协作&a…

38-1 防火墙了解

一、防火墙的概念: 防火墙(Firewall),也称防护墙,是由Check Point创立者Gil Shwed于1993年发明并引入国际互联网(US5606668 [A]1993-12-15)。它是一种位于内部网络与外部网络之间的网络安全系统,是一项信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。…

4个可将 iPhone iPad iPod 修复至正常状态的 iOS 系统恢复软件

许多iOS用户对操作系统问题感到恐慌&#xff0c;例如iPhone卡在恢复模式、白屏死机、黑屏死机、iOS系统损坏、iTunes连接屏幕、iPhone数据丢失等。这些状态通常很无聊&#xff0c;因为您无法使用 iPhone 执行任何操作。 4个可将 iPhone iPad iPod 修复至正常状态的 iOS 系统恢复…

【Unity 组件思想-预制体】

【Unity 组件思想-预制体】 预制体&#xff08;Prefab&#xff09;是Unity中一种特殊的组件 特点和用途&#xff1a; 重用性&#xff1a; 预制体允许开发者创建可重复使用的自定义游戏对象。这意味着你可以创建一个预制体&#xff0c;然后在场景中多次实例化它&#xff0c;…

sip转webrtc方案

技术选型 由于很多企业会议协议用的主要是webrtc&#xff0c;但是项目上很多时候的一些旧设备只支持sip协议&#xff0c;并不支持webrtc协议。所以sip和webrtc的相互转换就很有必要。 流媒体服务mediasoup本身并不支持sip协议。那么如何实现sip转webrtc呢&#xff1f; 根据调研…

我独自升级崛起下载教程 我独自升级崛起怎么一键下载

定于5月8日全球盛大发布的动作RPG力作《我独自升级崛起》&#xff0c;基于备受追捧的同名动画及网络漫画&#xff0c;誓为热情洋溢的游戏爱好者们呈献一场深度与广度兼具的冒险盛宴。这款游戏巧妙融合网络武侠元素&#xff0c;其创意十足的设计框架下&#xff0c;核心叙述聚焦于…

[极客大挑战 2019]PHP

1.通过目录扫描找到它的备份文件&#xff0c;这里的备份文件是它的源码。 2.源码当中涉及到的关键点就是魔术函数以及序列化与反序列化。 我们提交的select参数会被进行反序列化&#xff0c;我们要构造符合输出flag条件的序列化数据。 但是&#xff0c;这里要注意的就是我们提…

力扣每日一题109:有序链表转换二叉搜索树

题目 中等 给定一个单链表的头节点 head &#xff0c;其中的元素 按升序排序 &#xff0c;将其转换为 平衡 二叉搜索树。 示例 1: 输入: head [-10,-3,0,5,9] 输出: [0,-3,9,-10,null,5] 解释: 一个可能的答案是[0&#xff0c;-3,9&#xff0c;-10,null,5]&#xff0c;它…