Android-Retrofit源码分析2

335 阅读3分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

上一篇已经分析道创建retrofit对象,这篇开始分析具体的请求网络请求的demo

使用Demo

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("xxxxxxxx")
        .addConverterFactory(GsonConverterFactory.create())
        .build();
OrderApi api = retrofit.create(OrderApi.class);
//对发送请求进行封装,同时生成最终的网络请求对象
Call<OrderInfo> xxxx = api.getOrderDetailByNo("xxxx");

retrofit.create(XXXX.class);

//通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
public <T> T create(final Class<T> service) {
  validateServiceInterface(service);
  //使用动态代理技术拿到网络请求接口实例上的所有注解
  return (T)
      Proxy.newProxyInstance(
          service.getClassLoader(), //动态生成接口的实现类
          new Class<?>[] {service},//动态创建实例
          new InvocationHandler() { //将代理类的实现交给 InvocationHandler类作为具体的实现
            private final Platform platform = Platform.get();
            private final Object[] emptyArgs = new Object[0];

// 在 InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作 :如统计执行时间、进行初始化和清理、对接口调用进行检查等。 
            @Override
            public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                throws Throwable {
              if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
              }
              args = args != null ? args : emptyArgs;
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

使用动态代理的好处:

  • OrderApi对象调用getOrderDetailByNo(xxx)接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理
  • 获得网络请求接口实例上的所有注解
  • 更方便封装ServiceMethod

loadServiceMethod(method)方法讲解

ServiceMethod<?> loadServiceMethod(Method method) {
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;
  //设置线程同步锁
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    // ServiceMethod类对象采用了单例模式进行创建。即创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例。若没缓存,则通过建造者模式创建 serviceMethod 对象
    if (result == null) {
      result = ServiceMethod.parseAnnotations(this, method);
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}

loadServiceMeyhod这个对象就是读取网络请求接口里的方法,并根据前面配置好的属性去配置ServiceMeyhod这个对象。

他会设置一个同步锁,设置一个同步锁就可以保证不同的线程去读取LinkedHashMap缓存的时候不会造成数据的不安全性。然后调用缓存当中的get方法,ServiceMeyhod这个类通过单例进行创建,也就是创建ServiceMeyhod这个对象之前,他会判断LinkedHashMap缓存当中是否有之前创建过的网络请求实例。如果没有缓存,他就设为空,调用Builder模式来创建一个ServiceMeyhod对象并进行缓存,就是调用他的put方法将他传入缓存当中。所以说,创建实例的缓存机制它的核心做法就是使用单例模式实现ServiceMeyhod的唯一性,然后这个ServiceMeyhod对象对应网络请求接口里的方法。

ServiceMethod生成实例的过程

abstract class ServiceMethod<T> {
  //解析注解
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //解析注解获得请求的工厂对象
    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);
  }

  abstract @Nullable T invoke(Object[] args);
}
inal class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;

  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
  }  
}
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) {
    Type[] parameterTypes = method.getGenericParameterTypes();
    Type responseType =
        Utils.getParameterLowerBound(
            0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
    if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
      responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
      continuationWantsResponse = true;
    } 
    adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
    annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
  } else {
    adapterType = method.getGenericReturnType();
  }

  CallAdapter<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);
  Type responseType = callAdapter.responseType();
  if (responseType == okhttp3.Response.class) {
    throw methodError(
        method,
        "'"+ getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  if (responseType == Response.class) {
    throw methodError(method, "Response must include generic type (e.g., Response<String>)");
  }
  if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
    throw methodError(method, "HEAD method must use Void as response type.");
  }

  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);

  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  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 {
    return (HttpServiceMethod<ResponseT, ReturnT>)
        new SuspendForBody<>(
            requestFactory,
            callFactory,
            responseConverter,
            (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
            continuationBodyNullable);
  }
}