Retrofit 源码学习与使用

预习

  • 动态代理
  • 反射

本文主要对retrofit的源码进行学习,了解,学习其设计模式,与实现方式。

retrofit 的基本用法:

  1. Retrofit turns your HTTP API into a Java interface.
    (将HTTP API转换为Java接口。)
public interface GitHubService {
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}
复制代码
  1. The Retrofit class generates an implementation of the GitHubService interface.
    (Retrofit类生成GitHubService接口的实现。)
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);
复制代码
  1. Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.
    (创建的GitHubService的每个调用都可以向远程web服务器发出同步或异步的HTTP请求。)
Call> repos = service.listRepos("octocat");
复制代码



A : service接口的构建

  1. 首先创建一个service的接口类。
  2. 指定请求方式 常见的有GET,POST,PUT,DELETE...,注意大小写。
  3. 配置请求地址,注意path的配置规则(见retrofit 使用教程的7.2)
BaseUrl 和URL有关的注解中提供的值 最后结果
http://localhost:4567/path/to/other/ /post http://localhost:4567/post
http://localhost:4567/path/to/other/ post http://localhost:4567/path/to/other/post
http://localhost:4567/path/to/other/ github.com/ikidou github.com/ikidou
  • 如果你在注解中提供的url是完整的url,则url将作为请求的url。
  • 如果你在注解中提供的url是不完整的url,且不以 / 开头,则请求的url为baseUrl+注解中提供的值
  • 如果你在注解中提供的url是不完整的url,且以 / 开头,则请求的url为baseUrl的主机部分+注解中提供的值
  1. 指定请求的回调对象,默认返回retrofit的Call对象,这里我们可以
  • 通过实现retrofit的CallAdapter 接口,来自定义我们的返回对象。
  • 再继承CallAdapter.Factory生成我们自己的Factory,在get()方法返回我们自定义的CallAdapter。
  • 最后调用Retrofit.Builder的addCallAdapterFactory(Factory)
  1. 指定请求结束后我们要接收的类型,如:okHttp返回默认的是ResponseBody,通过Retrofit的Converter可以转换为我们需要的 string 或 反序列化为java Bean对象等。
  • 定义一个MyConvert类实现retrofit的Converter接口。
  • 定义一个MyConvertFactory继承retrofit的Converter.Factory,实现responseBodyConverter()返回我们自定义的MyConvert类。
  • 使用Retrofit.Builder.addConverterFactory(new MyConvertFactory())添加我们自定义的Factory.
  1. 定义我们请求的方法名字。
  2. 请求参数的注解 见(见retrofit 使用教程的第三类:参数类

  1. 请求参数的名字
  2. 参数类型
  3. 参数名称



B : retrofit的构建,源码分析

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
复制代码

我们可以看到retrofit的构建使用了builder模式。

1. 看一下Retrofit.Builder类:

/**
   * Build a new {@link Retrofit}.
   * 

* Calling {@link #baseUrl} is required before calling {@link #build()}. All other methods * are optional. */ public static final class Builder { private final Platform platform; private @Nullable okhttp3.Call.Factory callFactory; private HttpUrl baseUrl; private final List converterFactories = new ArrayList<>(); private final List adapterFactories = new ArrayList<>(); private @Nullable Executor callbackExecutor; private boolean validateEagerly; ... } 复制代码

从源码可以看到:

  • 从注释看到baseUrl()必须在build()之前调用,其它可以随意。
  • platform 指定调用的平台,这里我们使用的是Android.
  • callFactory okhttp3的Call.Factory
  • baseUrl 请求的root地址
  • converterFactories 存储我们自定义的和系统默认提供的convertFactory见上面的A.5
  • adapterFactories 存储我们自定义的和系统默认提供的adapterFactory 见上面的A.4
  • callbackExecutor 线程调用类
  • validateEagerly 为true时做一些预处理操作

2. build()方法的实现

  /**
     * Create the {@link Retrofit} instance using the configured values.
     * 

* Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link * OkHttpClient} will be created and used. */ //通过配置参数创建一个Retrofit的实例,如果没有配置HttpClient也没有配置CallFactory将采用默认的OkHttpClient public Retrofit build() { if (baseUrl == null) { // baseUrl不能为空 throw new IllegalStateException("Base URL required."); } //配置HttpClient,可以看出retrofit默认采用OkHttpClient okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } //指定callback回调方法的执行器,这里的platform是Android平台,可以看出默认下面的Android--Platform的MainThreadExecutor Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // Make a defensive copy of the adapters and add the default Call adapter. //将我们自定义的adapterFactory添加到集合中 List adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. //将我们自定义的convertFactory添加到集合中 List converterFactories = new ArrayList<>(this.converterFactories); // 返回Retrofit return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); } 复制代码

Android--Platform

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
复制代码

经过build()操作后,我们配置好了一个我们想要的retrofit,接下来我们来看看这些配置是如何生效的,我们通过

GitHubService service = retrofit.create(GitHubService.class);
复制代码

来生成我们service接口的实现类。我们来看create()方法。

3. retrofit.create()

 public  T create(final Class 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, @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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
复制代码 
   
  • validateEagerly 为true时会走 eagerlyValidateMethods(service)
  private void eagerlyValidateMethods(Class service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
复制代码

这里我们看到,是对ServiceMethod做的缓存处理。如果缓存中存在直接返回。

  • 接下来我们看见采用了动态代理的模式来创建service接口的实现类。
  • 如果是platform的方法直接return
  • 如果是我们service接口内的方法,我们看到通过上面的loadServiceMethod(method)来创建了一个ServiceMethod类,我们来看ServiceMethod类做了那些处理。

4. ServiceMethod

我们看到ServiceMethod也是采用Builder模式来构建。

/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod {
  // Upper and lower characters, digits, underscores, and hyphens, starting with a character.
  static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
  //请求地址中{}的正则匹配表达式
  static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  //参数名称的正常匹配
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

  final okhttp3.Call.Factory callFactory;//okhttp3.Call.Factory
  final CallAdapter callAdapter;//返回对象适配器
  private final HttpUrl baseUrl;//根地址
  private final Converter responseConverter;//reponseBody转换类
  private final String httpMethod;//请求方式,PUT,POST...
  private final String relativeUrl;//相对地址
  private final Headers headers;//请求头
  private final MediaType contentType;//请求的Content-Type
  private final boolean hasBody;//是否有请求消息体
  private final boolean isFormEncoded;//是否进行参数编码
  private final boolean isMultipart;// 上传时使用
  private final ParameterHandler[] parameterHandlers;//请求参数注解的封装对象

  ServiceMethod(Builder builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl();
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod;
    this.relativeUrl = builder.relativeUrl;
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;
  }
  ...
}
复制代码

接着来看 build() 方法

    public ServiceMethod build() {
       // [1] 创建CallAdapter,并得到返回的对象
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
      //[2] 创建ResponseConverte,对返回的数据进行处理
      responseConverter = createResponseConverter();
      //[3]遍历方法注解,获取具体的配置参数
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
        ...
        //[4] 方法中参数注解的处理
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        ...
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
       ...
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }
复制代码

上面的ServiceMethod.build()方法大概进行了如下操作:

  • [1] 创建CallAdapter,并得到返回的对象
  • [2] 创建ResponseConverte,对返回的数据进行处理
  • [3] 遍历方法注解,获取具体的配置参数
  • [4] 方法中参数注解的处理

接下来我们具体看看是如何实现的

[1] createCallAdapter()

 private CallAdapter createCallAdapter() {
        //获取方法的完整信息的返回值
      Type returnType = method.getGenericReturnType();
      ...
      //获得注解
      Annotation[] annotations = method.getAnnotations();
      ...
      return (CallAdapter) retrofit.callAdapter(returnType, annotations);
      ...
    }
复制代码

可以看到实际上是调用了retrofit.callAdapter(returnType, annotations)方法

 public CallAdapter callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  public CallAdapter nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    ...
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
        ...
  }
复制代码

从上面最终调用的nextCallAdapter方法,adapterFactories.get(i).get(returnType, annotations, this)看到,最终返回我们添加到adapterFactories的CallAdapterFactory.get()对象就是我们自定义的CallAdapter,注意这里是有排序概念的,排在前面的优先匹配。

再通过responseType = callAdapter.responseType();将我们自己定义的call对象,或Obserable对象,或其他需要类型返回,见上面图A.④。

[2] createResponseConverter()

 private Converter createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }
复制代码

再看retrofit.responseBodyConverter(responseType, annotations)

 public  Converter responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

  public  Converter nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
        ...
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter) converter;
      }
    }
    ...
  }
复制代码

这里我们最终看到通过converterFactories.get(i).responseBodyConverter(type, annotations, this)方法,返回我们自定义的泛型对象见上面图A.⑤,通常是我们反序列化操作转换后的对象,或根据需要过滤一些数据,返回有用的数据。

[3] parseMethodAnnotation(annotation)

在这里处理方法上面的注解,获取到请求方式见上面图A.②,并对不同的请求方式做相应处理。

  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);
        if (!Void.class.equals(responseType)) {
          throw methodError("HEAD method must use Void as response type.");
        }
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError("@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError("Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
复制代码

接下来看一下 parseHttpMethodAndPath()

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      ...
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // Get the relative URL path and existing query string, if present.
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }
      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

复制代码

我们看到这里将获取到的请求方式httpMethod,是否有hasBody,还有地址路径,headers,还有地址中含有的请求参数,等等,都赋值给ServiceMethod.Builder的相应属性。

[4] parameterHandlers[]的赋值操作

在ServiceMethod.Build(Retrofit retrofit, Method method)时我们看一下

  Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
复制代码
  • methodAnnotations 获得method上的所有注解
  • parameterTypes 获得所有的参数类型,String ,int ...
  • parameterAnnotationsArray 获得参数的注解集合

再看

int parameterCount = parameterAnnotationsArray.length;
        //构建一个ParameterHandler集合,
      parameterHandlers = new ParameterHandler[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
      //获取第p个参数类型
        Type parameterType = parameterTypes[p];
        ...
        //获取第p个参数注解集合
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
       ...
       //构建一个ParameterHandler对象
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

复制代码

看看 parseParameter(p, parameterType, parameterAnnotations)

  private ParameterHandler parseParameter(
        int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler result = null;
      for (Annotation annotation : annotations) {
      
        ParameterHandler annotationAction = parseParameterAnnotation(p, parameterType, annotations,annotation);
        
        }
            ...

      return result;
    }
    
复制代码

接着往下看parseParameterAnnotation(p, parameterType, annotations,annotation)

private ParameterHandler parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
      if (annotation instanceof Url) {
        if (gotUrl) {
          throw parameterError(p, "Multiple @Url method annotations found.");
        }
        if (gotPath) {
          throw parameterError(p, "@Path parameters may not be used with @Url.");
        }
        if (gotQuery) {
          throw parameterError(p, "A @Url parameter must not come after a @Query");
        }
        if (relativeUrl != null) {
          throw parameterError(p, "@Url cannot be used with @%s URL", httpMethod);
        }

        gotUrl = true;

        if (type == HttpUrl.class
            || type == String.class
            || type == URI.class
            || (type instanceof Class && "android.net.Uri".equals(((Class) type).getName()))) {
          return new ParameterHandler.RelativeUrl();
        } else {
          throw parameterError(p,
              "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
        }

      } else if (annotation instanceof Path) {
        if (gotQuery) {
          throw parameterError(p, "A @Path parameter must not come after a @Query.");
        }
        if (gotUrl) {
          throw parameterError(p, "@Path parameters may not be used with @Url.");
        }
        if (relativeUrl == null) {
          throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
        }
        gotPath = true;

        Path path = (Path) annotation;
        String name = path.value();
        validatePathName(p, name);

        Converter converter = retrofit.stringConverter(type, annotations);
        return new ParameterHandler.Path<>(name, converter, path.encoded());

      } else if (annotation instanceof Query) {
        Query query = (Query) annotation;
        String name = query.value();
        boolean encoded = query.encoded();

        Class rawParameterType = Utils.getRawType(type);
        gotQuery = true;
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          if (!(type instanceof ParameterizedType)) {
            throw parameterError(p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + ")");
          }
          ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
          Converter converter =
              retrofit.stringConverter(iterableType, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
          Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter converter =
              retrofit.stringConverter(arrayComponentType, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded).array();
        } else {
          Converter converter =
              retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Query<>(name, converter, encoded);
        }

      } else if (annotation instanceof QueryName) {
        QueryName query = (QueryName) annotation;
        boolean encoded = query.encoded();

        Class rawParameterType = Utils.getRawType(type);
        gotQuery = true;
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          if (!(type instanceof ParameterizedType)) {
            throw parameterError(p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + ")");
          }
          ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
          Converter converter =
              retrofit.stringConverter(iterableType, annotations);
          return new ParameterHandler.QueryName<>(converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
          Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter converter =
              retrofit.stringConverter(arrayComponentType, annotations);
          return new ParameterHandler.QueryName<>(converter, encoded).array();
        } else {
          Converter converter =
              retrofit.stringConverter(type, annotations);
          return new ParameterHandler.QueryName<>(converter, encoded);
        }

      } else if (annotation instanceof QueryMap) {
        Class rawParameterType = Utils.getRawType(type);
        if (!Map.class.isAssignableFrom(rawParameterType)) {
          throw parameterError(p, "@QueryMap parameter type must be Map.");
        }
        Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
        if (!(mapType instanceof ParameterizedType)) {
          throw parameterError(p, "Map must include generic types (e.g., Map)");
        }
        ParameterizedType parameterizedType = (ParameterizedType) mapType;
        Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
        if (String.class != keyType) {
          throw parameterError(p, "@QueryMap keys must be of type String: " + keyType);
        }
        Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
        Converter valueConverter =
            retrofit.stringConverter(valueType, annotations);

        return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());

      } else if (annotation instanceof Header) {
        Header header = (Header) annotation;
        String name = header.value();

        Class rawParameterType = Utils.getRawType(type);
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          if (!(type instanceof ParameterizedType)) {
            throw parameterError(p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + ")");
          }
          ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
          Converter converter =
              retrofit.stringConverter(iterableType, annotations);
          return new ParameterHandler.Header<>(name, converter).iterable();
        } else if (rawParameterType.isArray()) {
          Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter converter =
              retrofit.stringConverter(arrayComponentType, annotations);
          return new ParameterHandler.Header<>(name, converter).array();
        } else {
          Converter converter =
              retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Header<>(name, converter);
        }

      } else if (annotation instanceof HeaderMap) {
        Class rawParameterType = Utils.getRawType(type);
        if (!Map.class.isAssignableFrom(rawParameterType)) {
          throw parameterError(p, "@HeaderMap parameter type must be Map.");
        }
        Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
        if (!(mapType instanceof ParameterizedType)) {
          throw parameterError(p, "Map must include generic types (e.g., Map)");
        }
        ParameterizedType parameterizedType = (ParameterizedType) mapType;
        Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
        if (String.class != keyType) {
          throw parameterError(p, "@HeaderMap keys must be of type String: " + keyType);
        }
        Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
        Converter valueConverter =
            retrofit.stringConverter(valueType, annotations);

        return new ParameterHandler.HeaderMap<>(valueConverter);

      } else if (annotation instanceof Field) {
        if (!isFormEncoded) {
          throw parameterError(p, "@Field parameters can only be used with form encoding.");
        }
        Field field = (Field) annotation;
        String name = field.value();
        boolean encoded = field.encoded();

        gotField = true;

        Class rawParameterType = Utils.getRawType(type);
        if (Iterable.class.isAssignableFrom(rawParameterType)) {
          if (!(type instanceof ParameterizedType)) {
            throw parameterError(p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + ")");
          }
          ParameterizedType parameterizedType = (ParameterizedType) type;
          Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
          Converter converter =
              retrofit.stringConverter(iterableType, annotations);
          return new ParameterHandler.Field<>(name, converter, encoded).iterable();
        } else if (rawParameterType.isArray()) {
          Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
          Converter converter =
              retrofit.stringConverter(arrayComponentType, annotations);
          return new ParameterHandler.Field<>(name, converter, encoded).array();
        } else {
          Converter converter =
              retrofit.stringConverter(type, annotations);
          return new ParameterHandler.Field<>(name, converter, encoded);
        }

      } else if (annotation instanceof FieldMap) {
        if (!isFormEncoded) {
          throw parameterError(p, "@FieldMap parameters can only be used with form encoding.");
        }
        Class rawParameterType = Utils.getRawType(type);
        if (!Map.class.isAssignableFrom(rawParameterType)) {
          throw parameterError(p, "@FieldMap parameter type must be Map.");
        }
        Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
        if (!(mapType instanceof ParameterizedType)) {
          throw parameterError(p,
              "Map must include generic types (e.g., Map)");
        }
        ParameterizedType parameterizedType = (ParameterizedType) mapType;
        Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
        if (String.class != keyType) {
          throw parameterError(p, "@FieldMap keys must be of type String: " + keyType);
        }
        Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
        Converter valueConverter =
            retrofit.stringConverter(valueType, annotations);

        gotField = true;
        return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded());

      } else if (annotation instanceof Part) {
        if (!isMultipart) {
          throw parameterError(p, "@Part parameters can only be used with multipart encoding.");
        }
        Part part = (Part) annotation;
        gotPart = true;

        String partName = part.value();
        Class rawParameterType = Utils.getRawType(type);
        if (partName.isEmpty()) {
          if (Iterable.class.isAssignableFrom(rawParameterType)) {
            if (!(type instanceof ParameterizedType)) {
              throw parameterError(p, rawParameterType.getSimpleName()
                  + " must include generic type (e.g., "
                  + rawParameterType.getSimpleName()
                  + ")");
            }
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
            if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
              throw parameterError(p,
                  "@Part annotation must supply a name or use MultipartBody.Part parameter type.");
            }
            return ParameterHandler.RawPart.INSTANCE.iterable();
          } else if (rawParameterType.isArray()) {
            Class arrayComponentType = rawParameterType.getComponentType();
            if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
              throw parameterError(p,
                  "@Part annotation must supply a name or use MultipartBody.Part parameter type.");
            }
            return ParameterHandler.RawPart.INSTANCE.array();
          } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
            return ParameterHandler.RawPart.INSTANCE;
          } else {
            throw parameterError(p,
                "@Part annotation must supply a name or use MultipartBody.Part parameter type.");
          }
        } else {
          Headers headers =
              Headers.of("Content-Disposition", "form-data; name=\"" + partName + "\"",
                  "Content-Transfer-Encoding", part.encoding());

          if (Iterable.class.isAssignableFrom(rawParameterType)) {
            if (!(type instanceof ParameterizedType)) {
              throw parameterError(p, rawParameterType.getSimpleName()
                  + " must include generic type (e.g., "
                  + rawParameterType.getSimpleName()
                  + ")");
            }
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
            if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
              throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
                  + "include a part name in the annotation.");
            }
            Converter converter =
                retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
            return new ParameterHandler.Part<>(headers, converter).iterable();
          } else if (rawParameterType.isArray()) {
            Class arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
            if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
              throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
                  + "include a part name in the annotation.");
            }
            Converter converter =
                retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
            return new ParameterHandler.Part<>(headers, converter).array();
          } else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
            throw parameterError(p, "@Part parameters using the MultipartBody.Part must not "
                + "include a part name in the annotation.");
          } else {
            Converter converter =
                retrofit.requestBodyConverter(type, annotations, methodAnnotations);
            return new ParameterHandler.Part<>(headers, converter);
          }
        }

      } else if (annotation instanceof PartMap) {
        if (!isMultipart) {
          throw parameterError(p, "@PartMap parameters can only be used with multipart encoding.");
        }
        gotPart = true;
        Class rawParameterType = Utils.getRawType(type);
        if (!Map.class.isAssignableFrom(rawParameterType)) {
          throw parameterError(p, "@PartMap parameter type must be Map.");
        }
        Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
        if (!(mapType instanceof ParameterizedType)) {
          throw parameterError(p, "Map must include generic types (e.g., Map)");
        }
        ParameterizedType parameterizedType = (ParameterizedType) mapType;

        Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
        if (String.class != keyType) {
          throw parameterError(p, "@PartMap keys must be of type String: " + keyType);
        }

        Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
        if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(valueType))) {
          throw parameterError(p, "@PartMap values cannot be MultipartBody.Part. "
              + "Use @Part List or a different value type instead.");
        }

        Converter valueConverter =
            retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);

        PartMap partMap = (PartMap) annotation;
        return new ParameterHandler.PartMap<>(valueConverter, partMap.encoding());

      } else if (annotation instanceof Body) {
        if (isFormEncoded || isMultipart) {
          throw parameterError(p,
              "@Body parameters cannot be used with form or multi-part encoding.");
        }
        if (gotBody) {
          throw parameterError(p, "Multiple @Body method annotations found.");
        }

        Converter converter;
        try {
          converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
        } catch (RuntimeException e) {
          // Wide exception range because factories are user code.
          throw parameterError(e, p, "Unable to create @Body converter for %s", type);
        }
        gotBody = true;
        return new ParameterHandler.Body<>(converter);
      }

      return null; // Not a Retrofit annotation.
    }

复制代码

这么超长的代码,将我们方法参数的注解,参数类型,参数值都拿到,封装为 ParameterHandler 并保存到ParameterHandler[] parameterHandlers集合。

至此,我们将我们创建的service接口所调用方法中的请求方式,请求路径,返回值,请求参数等都获取到了,并存储到一个ServiceMethod对象中。

接下来我们再回到 retrofit.Create()

  public  T create(final Class 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, @Nullable Object[] args)
              throws Throwable {
          ...
          //这里最终返回到Retrofit中的ServiceMethod,来存储我们构建的serviceMethod
            ServiceMethod serviceMethod =
                (ServiceMethod) loadServiceMethod(method);
            //再看OkHttpCall
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }
复制代码 
   

5. OkHttpCall

将我们上面构建的serviceMethod 与参数传进来

  OkHttpCall(ServiceMethod serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }
复制代码

最后通过serviceMethod.callAdapter.adapt(okHttpCall)就创建好了我们service的一个实现类。

再看看**callAdapter.adapt(okHttpCall)**这里的callAdapter是们自定义的callAdapter对象,Android默认的是Call<>;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>,这里我们看看后一种情况下的实现方式。

RxJavaCallAdapterFactory-->RxJava2CallAdapter 这里我们看RxJava2CallAdapter的adapt()方法。

 @Override public Object adapt(Call call) {
    Observable> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);

    Observable observable;
    if (isResult) {
      observable = new ResultObservable<>(responseObservable);
    } else if (isBody) {
      observable = new BodyObservable<>(responseObservable);
    } else {
      observable = responseObservable;
    }

    if (scheduler != null) {
      observable = observable.subscribeOn(scheduler);
    }

    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }
复制代码

我们看到但isAsync是异步情况下时,new CallEnqueueObservable<>(call),创建了一个CallEnqueueObservable 对象,并将retrofit的okhttpCall继续传进来.

我们知道在RxJava,Observable的subscribe()触发了代码执行的操作。来看:

@SchedulerSupport(SchedulerSupport.NONE)
    @Override
    public final void subscribe(Observer observer) {
            ...
  @Override public void enqueue(final Callback callback) {
    checkNotNull(callback, "callback == null");

//这里创建一个okhttp3.Call的call对象
    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 {
        //这里看到通过createRawCall() 创建返回了一个call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    if (failure != null) {
      callback.onFailure(this, failure);
      return;
    }

    if (canceled) {
      call.cancel();
    }
//实际上就是通过okhttp3.call来请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response response;
        try {
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        callSuccess(response);
      }

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

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

      private void callSuccess(Response response) {
          callback.onResponse(OkHttpCall.this, response);
      ...
      }
  }
复制代码

createRawCall()

private okhttp3.Call createRawCall() throws IOException {
[1] 创建一个request 请求对象
    Request request = serviceMethod.toRequest(args);
    [2]调用newCall(request)返回一个okhttp3.Call 
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

复制代码

serviceMethod.toRequest(args)

 Request toRequest(@Nullable Object... args) throws IOException {
 
 //这里new了一个requestBuilder 将我们获取到的请求的相关信息传进去
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    //参数值解析
    ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;
        ...
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

//这里调用build() 
    return requestBuilder.build();
  }
复制代码 
   

下面看一下requestBuilder.build() 是如何创建一个request对象的

 Request build() {
    HttpUrl url;
    HttpUrl.Builder urlBuilder = this.urlBuilder;
    if (urlBuilder != null) {
      url = urlBuilder.build();
    } else {
      // No query parameters triggered builder creation, just combine the relative URL and base URL.
      //noinspection ConstantConditions Non-null if urlBuilder is null.
      url = baseUrl.resolve(relativeUrl);
      if (url == null) {
        throw new IllegalArgumentException(
            "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
      }
    }

    RequestBody body = this.body;
    if (body == null) {
      // Try to pull from one of the builders.
      if (formBuilder != null) {
        body = formBuilder.build();
      } else if (multipartBuilder != null) {
        body = multipartBuilder.build();
      } else if (hasBody) {
        // Body is absent, make an empty body.
        body = RequestBody.create(null, new byte[0]);
      }
    }

    MediaType contentType = this.contentType;
    if (contentType != null) {
      if (body != null) {
        body = new ContentTypeOverridingRequestBody(body, contentType);
      } else {
        requestBuilder.addHeader("Content-Type", contentType.toString());
      }
    }

    return requestBuilder
        .url(url)
        .method(method, body)
        .build();
  }

复制代码

接着看看call.enqueue()

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

复制代码

client.dispatcher().enqueue(new AsyncCall(responseCallback));

  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    
      runningAsyncCalls.add(call);
      //可以看到这里执行了网络请求,并通过call完成返回请求结果的回调。
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
复制代码

从上面可以看到,这里最终是通过创建一个okHttp3.Call对象,构建出一个网络请求的Request,发送网络请求,并调用了call.enqueue()最后将请求到的结果,返回到Retrofit的Callback对象。

package retrofit2;
public interface Callback {
  void onResponse(Call call, Response response);
  void onFailure(Call call, Throwable t);
复制代码

到这里一个请求就结束了。

总结

梳理一下整个过程:

  1. 书写我们的service请求接口,配置好请求路径,请求方式,参数配置等。
  2. 构建我们自定义的convert ,convertAdapter 。
  3. 构建retrofit对象,并添加我们的convertFactory,converAdapterFactory等。
  4. 通过retrofit的create()动态代理实现service接口的实现类
  5. 解析 网络请求接口的注解 配置 网络请求参数
  6. 通过 网络请求适配器 将 网络请求对象 进行平台适配
  7. 通过 网络请求执行器 发送网络请求
  8. 通过 数据转换器 解析服务器返回的数据
  9. 通过 回调执行器 切换线程(子线程 ->>主线程)
  10. 最后用户在主线程处理返回结果

参考文章

(参考使用了下面文章的部分内容与资源)

  • retrofit 官网
  • retrofit 使用教程
  • Android:手把手带你 深入读懂 Retrofit 2.0 源码

转载于:https://juejin.im/post/5b2c91cb51882574b55e5ae0

你可能感兴趣的:(移动开发,java,设计模式)