Registro de lectura de código fuente de actualización

imagen-20210819152814979

Instanciación de actualización

Genere instancias a partir del esquema del constructor.

  • plataforma: tipo de plataforma, para diferentes compatibilidades

  • callFactory: se usa para crear un modelo de llamada de método Call (puede ser asíncrono o síncrono, un poco como FutureTask, se usa para obtener el resultado de la llamada) y convertir la llamada de método en acceso Http.

  • baseUrl: dirección base. Generalmente representa un nombre de dominio o IP, y el nombre de dominio de identificación debe incluirse al final \para garantizar la precisión de la ruta. \El modo normal se optimiza si host + ruta aparece dos veces .

  • converterFactories: fábricas de serialización y deserialización, utilizadas para obtener Converter, cada fábrica tiene un tipo compatible personalizado;

    Al configurar la plataforma, el integrado se configurará BuiltInConverterspara garantizar la corrección de la conversión de tipo básico.

    final class BuiltInConverters extends Converter.Factory {
          
          
      @Override
      public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
          Retrofit retrofit) {
          
          
        if (type == ResponseBody.class) {
          
          
          if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
          
          
              // 原样返回
            return StreamingResponseBodyConverter.INSTANCE;
          }
            // 将结果缓存到 buffer 中,避免后续的IO
          return BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
          
          
            // 用来直接关闭连接,返回 null
          return VoidResponseBodyConverter.INSTANCE;
        }
        return null;
      }
     }
    
  • adaptorFactories: llame a la fábrica de adaptadores modelo para obtener CallAdapter (que admite la conversión de llamadas en tipos específicos), y cada fábrica tiene un tipo compatible personalizado. Es la capa externa de Converter, que primero ejecuta la llamada y luego la convierte al modelo de resultado de acuerdo con Converter.

    El adaptador está más preocupado por el patrón de comportamiento de la llamada.

  • callbackExecutor: llama al ejecutor, la clave para saber si es asíncrono.

  • validar ansiosamente: si analizar e inicializar el método de llamada por adelantado

La configuración predeterminada es OkHttpClient, Ejecutor vacío, adaptador de interfaz de retorno predeterminado (simplemente no haga nada, regrese tal como está), sin deserializador de serialización.

public static final class Builder {
    
    
  private Platform platform;
  private okhttp3.Call.Factory callFactory;
  private HttpUrl baseUrl;
  private List<Converter.Factory> converterFactories = new ArrayList<>();
  private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
  private Executor callbackExecutor;
  private boolean validateEagerly;
  public Retrofit build() {
    
    
      if (baseUrl == null) {
    
    
        throw new IllegalStateException("Base URL required.");
      }

      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
    
    
          // 默认就是 OkHttpClient,一家的
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
    
    
          // Java 的话,默认是 NULL
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      // 如果 callbackExecutor != null,那实际是做一层同步转异步调用的封装
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }
}
Plataforma

Platform garantiza la adaptabilidad de cada plataforma, principalmente a través de si la clase especial de carga informará un error.

private static Platform findPlatform() {
    
    
  try {
    
    
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
    
    
      return new Android();
    }
  } catch (ClassNotFoundException ignored) {
    
    
  }
  try {
    
    
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
    
    
  }
  try {
    
    
    Class.forName("org.robovm.apple.foundation.NSObject");
    return new IOS();
  } catch (ClassNotFoundException ignored) {
    
    
  }
  return new Platform();
}

Principalmente asegura si es necesario procesar el método predeterminado de la interfaz, el Ejecutor, etc.

Las clases de implementación predeterminadas son Java, Android e IOS.

imagen-20210819101521333

interfaz

En el momento de la inicialización, se genera un proxy de interfaz

validar ansiosamente == verdadero

En el momento de la inicialización, todos los métodos no predeterminados se extraen para generar un proxy de método (ServiceMethod) y se almacenan en caché. De lo contrario, diferir de la llamada real a la real.

Okhttp primero empaqueta la llamada al método real para garantizar el procesamiento de la llamada de red; luego CallAdapter la empaqueta (busque si es aplicable desde Retrofit) para realizar la llamada real (generalmente OkHttp Client).

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, 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)) {
    
    
              // 只有 Java 平台才能执行 default 方法
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
            // 加载方法代理
          ServiceMethod serviceMethod = loadServiceMethod(method);
            // 包装成 Http 调用
          OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            // 将调用模型封装为特定的模型,比如 java8 CompletedFuture、rxJava 的响应式等
            // 一般默认是 DefaultCallAdapterFactory,不做任何处理
            // 或自定义线程池情况下,ExecutorCallAdapterFactory 转为异步调用
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}

El resultado final puede ser el resultado que desea, o puede ser solo un paquete de llamadas Http. Depende de lo que haga el CallAdapter.

El propósito de hacer esto, creo, es también hacer algún procesamiento además de la solicitud http básica, como el procesamiento de fusibles Hystrix que usa nuestra empresa.

Por supuesto, también puede personalizar Adapter y AdapterFactory, llamarlos directamente al realizar la adaptación de llamadas y generar resultados comerciales.

Un JavaAdapter es algo así, pero devuelve el resultado en un CompletedFuture.

Reequipamiento - Página 1

Método de servicio

Una capa de empaquetado para el método, lo más importante es analizar las anotaciones y la información de metadatos sobre Retrofit en el método y luego generar un conjunto de analizadores, convertidores, etc.

Cuando llame, convierta los parámetros reales en Solicitud Http; si la llamada es exitosa, convierta el resultado en un tipo de negocio específico.

Request toRequest(Object... args) throws IOException {
    
    }
T toResponse(ResponseBody body) throws IOException {
    
    }
static final class Builder<T> {
    
    
   // 基础属性, 借助 retrofit 的一些设置,以及 Method 的其他信息
  final Retrofit retrofit;
  final Method method;
  final Annotation[] methodAnnotations;
  final Annotation[][] parameterAnnotationsArray;
  final Type[] parameterTypes;
// 解析方法的元数据
  Type responseType;
  boolean gotField;
  boolean gotPart;
  boolean gotBody;
  boolean gotPath;
  boolean gotQuery;
  boolean gotUrl;
  String httpMethod;
  boolean hasBody;
  boolean isFormEncoded;
  boolean isMultipart;
  String relativeUrl;
  Headers headers;
  MediaType contentType;
  Set<String> relativeUrlParamNames;
  ParameterHandler<?>[] parameterHandlers;
  Converter<ResponseBody, T> responseConverter;
  CallAdapter<?> callAdapter;

  public Builder(Retrofit retrofit, Method method) {
    
    
    this.retrofit = retrofit;
    this.method = method;
    this.methodAnnotations = method.getAnnotations();
    this.parameterTypes = method.getGenericParameterTypes();
    this.parameterAnnotationsArray = method.getParameterAnnotations();
  }
}

construir

El método de creación de instancias también es el patrón Builder.

public ServiceMethod build() {
    
    
   // 根据返回类型和注解,在 Retrofit 配置的列表中找到匹配的 callAdapter
   // 默认的请求方法返回值都是Call<T>, 可以继承CallAdapter.Factory来实现自定义的返回值类型
  callAdapter = createCallAdapter();
  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?");
  }
   // 根据返回类型和注解,在 Retrofit 配置的列表中找到匹配的 converter
  responseConverter = createResponseConverter();

  for (Annotation annotation : methodAnnotations) {
    
    
      // 处理注解,来填充元数据信息,比如 GET、PUT、isMultipart、isFormEncoded
      // 如果出现不符合的情况,直接报错
    parseMethodAnnotation(annotation);
  }
 // 省略一些异常情况的检查
  。。。。。

  int parameterCount = parameterAnnotationsArray.length;
    // 负责将参数填充到对应 Http 的请求模型中,比如 Body、Header、URLParam等
  parameterHandlers = new ParameterHandler<?>[parameterCount];
  for (int p = 0; p < parameterCount; p++) {
    
    
    Type parameterType = parameterTypes[p];
      // 不能处理泛型
    if (Utils.hasUnresolvableType(parameterType)) {
    
    
      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);
  }

  // 省略参数解析的异常检查
......
  return new ServiceMethod<>(this);
}

OkHttpLlamar

Retrofit convierte una llamada de método en una llamada Http a través de la interfaz de llamada, que puede ser una llamada síncrona para ejecutar o una llamada asíncrona para poner en cola (devolución de llamada).

public interface Call<T> extends Cloneable {
    
    
  Response<T> execute() throws IOException;
  void enqueue(Callback<T> callback);
  Request request();

La devolución de llamada en realidad refleja la devolución de llamada, el procesamiento integrado de éxito o falla.

Al igual que cuando se usa un JavaAdapter, el resultado se convierte en un CompletedFuture.

En términos generales, en la implementación predeterminada de retrofit, se usa poner en cola cuando hay un grupo de subprocesos.

Finalmente se obtiene una Call, siempre que se llame al método de ejecución se generará una petición Http y se obtendrá el resultado.

Modernización - página 2

Solicitud de compilación y llamada OkHttp
private okhttp3.Call createRawCall() throws IOException {
    
    
    // 像前面说的,通过解析器、转换器等,将参数转为 Request 参数
  Request request = serviceMethod.toRequest(args);
    // 构建 okhttp3 的调用,毕竟使用 OkHttp 请求的。
  okhttp3.Call call = serviceMethod.callFactory.newCall(request);
  if (call == null) {
    
    
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}

public synchronized Request request() {
    
    
    okhttp3.Call call = rawCall;
    if (call != null) {
    
    
      return call.request();
    }
    if (creationFailure != null) {
    
    
      if (creationFailure instanceof IOException) {
    
    
        throw new RuntimeException("Unable to create request.", creationFailure);
      } else {
    
    
        throw (RuntimeException) creationFailure;
      }
    }
    try {
    
    
      return (rawCall = createRawCall()).request();
    } catch (RuntimeException e) {
    
    
      creationFailure = e;
      throw e;
    } catch (IOException e) {
    
    
      creationFailure = e;
      throw new RuntimeException("Unable to create request.", e);
    }
  }
ejecución síncrona
public Response<T> execute() throws IOException {
    
    
  okhttp3.Call call;

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

    if (creationFailure != null) {
    
    
        // 说明之前构建过 Call 和 Request,且失败了
      if (creationFailure instanceof IOException) {
    
    
        throw (IOException) creationFailure;
      } else {
    
    
        throw (RuntimeException) creationFailure;
      }
    }

    call = rawCall;
    if (call == null) {
    
    
      try {
    
    
        call = rawCall = createRawCall();
      } catch (IOException | RuntimeException e) {
    
    
        creationFailure = e;
        throw e;
      }
    }
  }

  if (canceled) {
    
    
    call.cancel();
  }
 // 执行返回结果
  return parseResponse(call.execute());
}
puesta en cola asíncrona
public void enqueue(final Callback<T> callback) {
    
    
  if (callback == null) throw new NullPointerException("callback == null");

  okhttp3.Call call;
  Throwable failure;

  synchronized (this) {
    
    
   // 同上

  call.enqueue(new okhttp3.Callback() {
    
    
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
        throws IOException {
    
    
      Response<T> response;
      try {
    
    
          // 成功,转换结果
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
    
    
          // 失败流程
        callFailure(e);
        return;
      }
          // 成功流程
      callSuccess(response);
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
    
    
      try {
    
    
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
    
    
        t.printStackTrace();
      }
    }

    private void callFailure(Throwable e) {
    
    
      try {
    
    
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
    
    
        t.printStackTrace();
      }
    }

    private void callSuccess(Response<T> response) {
    
    
      try {
    
    
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
    
    
        t.printStackTrace();
      }
    }
  });
}
Convertir resultado parseResponse

Convierta la respuesta de OkHttp en la propia respuesta de Retrofit

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();
  if (code < 200 || code >= 300) {
    
    
    try {
    
    
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
    
    
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    
    
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    
    
    T body = serviceMethod.toResponse(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;
  }
}

Convertidor, adaptador

Los paquetes de extensión correspondientes se pueden introducir para admitir diferentes escenarios.

Como Jackson, Gson, FastJson Converter;

Por ejemplo, un adaptador compatible con la programación receptiva Java8 CompletedFuture y RxJava.

El adaptador juzga por tipo de valor de retorno de forma predeterminada, siempre que se adapte a un tipo específico. Este tipo no es un modelo de resultado empresarial, sino un modelo de invocación.

Generalmente es Call, y Java8 es CompletedFuture, y el resultado se obtiene a través de CompletedFuture.get.

Supongo que te gusta

Origin blog.csdn.net/jiangxiayouyu/article/details/119803290
Recomendado
Clasificación