Retrofit相关源码解析

Retrofit这个开源库出来也有一定年头了,记得之前还是在V1.0的版本的时候,之前在三月份也写过一个Retrofit的使用简析,那会儿正是1.0向2.0过渡的时候,所以新版本老版本对比了一下!时至今日,相关文章已经层出不穷了,今天主要是打开它的源码,了解一些细节的问题!

准备工作

基于版本:

compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'

相关问题:

1、Retrofit是使用注解确定对应的请求方式和参数的,那么具体的url是怎么产生出来的的呢?

2、我们定义的是一个接口,那么Retrofit又是怎么生成对应的实现类的呢?

3、网络请求V2.0开始统一使用OkHttp了,那么异步回调到主线程是如何实现的?

4、同一个方法,支持Call<T> 的返回类型,又可以支持Observable<T>的返回类型,这个又是如何实现的?

5、同一个方法,支持不同的转换(GsonJacksonMoshiFastJson等等),这个又是如何实现的呢?

带着这些问题,我们可以更好的进行相关的源码分析

第一部分 Retrofit && ServiceMethod的创建

从Retrofit的构建方法开始说起

new Retrofit.Builder()
        .baseUrl("http://10.0.60.115:60321/1.0/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(new OkHttpClient.Builder()
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        return chain.proceed(RequestUtils.createLoginJsonRequest(chain.request()));
                    }
                })
                .addNetworkInterceptor(
                        new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS))
                .build())
        .build()
        .create(LoginApi.class);

这里就是显而易见的builder模,通过Builder去构建我们需要的一些必要数据(比如说baseUrl,callAdapter,Conver等等),接下来看看Builder里面具体做了些什么!!

调用Retrofit内部的Builder的空参数构造方法!:

  public Builder() {
      this(Platform.get());
    }

Builder(Platform platform) {
      this.platform = platform;
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
}

在这里,又去调用了Platform.get()初始化了一个Platform,并把默认的转换器BuiltInConverters初始化并加入了集合中!!

那么问题来了,这个Platform是何方神圣,具体有撒作用??顺藤摸瓜,这里开始介绍内部的第一个神秘嘉宾!!

Platform 初始化

private static final Platform PLATFORM = findPlatform();//初始化`Platform`的静态方法

Platform字面意思就是平台啦,所以Platform相当于一个抽象类,这个类里面有对应的实现类:Android iOS Java 8对应的是各种具体平台。

  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();
  }

可以看到,在调用findPlatform()方法之后就回去判断初始化对应的具体平台,具体的实现类就是上面说到的三个,Android Java iOS,你没有看错,还有iOS的(这里是用的Swift),啧啧。。

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

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      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);
      }
    }
  }

各个不同的平台其实就是根据不同的环境初始化不同的MainThreadExecutor,像上面的Android平台当然就是获取主线程的Handler!!这里可以看到,在初始化Platform之后,通过Platform得到的ExecutorCallAdapterFactory的工厂的Executor其实就是运行在主线程的Executor

Builder的默认构造函数基本上讲完了!其实就是通过对应的平台构建了一个具体的Platform,通过这个Platform构建出了对应平台的主线程队列的线程池,方便后面的方法回调到主线程中!这里基本上也可以回答第三个问题了,异步怎么回调到主线程的!

添加baseUrl

public Builder baseUrl(HttpUrl baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

这里没撒说的,就是检测一下url的格式,然后完成赋值!

addConverterFactory && addCallAdapterFactory

/** Add converter factory for serialization and deserialization of objects. */
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

/**
 * Add a call adapter factory for supporting service method return types other than {@link
 * Call}.
 */
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
  adapterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

这里忍不住必须说两句了,这两个方法套路是完全一样——适配器模式,CallAdapter是请求Call对应的适配器,CallAdapter.Factory是创建对应CallAdapter的抽象工厂!! Converter是解析的转换器,这里提供了三种转换场景,responseBodyConverterrequestBodyConverterstringConverterConverter.Factory则是Convert的抽象工厂,这样利于我们的后期扩展,比如说外国人肯定没有写对应FastJsonCovert,但是它提供了工厂的嘛,我们继承这个抽象工厂,实现出来就好了!!

RxJavaCallAdapterFactory

在RxJavaCallAdapterFactory这个工厂中,又定义了两种 ,一种是SimpleCallAdapter另外一种是ResultCallAdapter,

    //SimpleCallAdapter
    @Override public <R> Observable<R> adapt(Call<R> call) {
  Observable<R> observable = Observable.create(new CallOnSubscribe<>(call)) //
      .flatMap(new Func1<Response<R>, Observable<R>>() {
        @Override public Observable<R> call(Response<R> response) {
          if (response.isSuccessful()) {
            return Observable.just(response.body());
          }
          return Observable.error(new HttpException(response));
        }
      });
  if (scheduler != null) {
    return observable.subscribeOn(scheduler);
  }
  return observable;
}

//ResultCallAdapter
@Override public <R> Observable<Result<R>> adapt(Call<R> call) {
  Observable<Result<R>> observable = Observable.create(new CallOnSubscribe<>(call)) //
      .map(new Func1<Response<R>, Result<R>>() {
        @Override public Result<R> call(Response<R> response) {
          return Result.response(response);
        }
      }).onErrorReturn(new Func1<Throwable, Result<R>>() {
        @Override public Result<R> call(Throwable throwable) {
          return Result.error(throwable);
        }
      });
  if (scheduler != null) {
    return observable.subscribeOn(scheduler);
  }
  return observable;
}

通俗的说其实就是根据返回值类型判断返回的Observable是否需要处理一下对应的Response!!使用flatMap()将其包装为一个新的Observable返回!!

Retrofit在创建的build()方法:

public Retrofit build() {
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }

  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  Executor callbackExecutor = this.callbackExecutor;
  if (callbackExecutor == 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);
  //添加完之后再添加一个defaultCallAdapterFactory
  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);
}

//这个方法是上面提到的platform里面的方法,通过这个方法,将主线程的线程池和ExecutorCallAdapterFactory关联起来了!!
  CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

到这里,Builder的创建过程分析完毕,总结起来就是创建出具体的Platform,通过具体的Platform创建出主线程的线程池,然后构建出默认的ExecutorCallAdapterFactory,另外就是添加对应的CallAdapter.Factory(比如说RxJavaCallAdapterFactory 等)和Converter.Factory!


生成接口的代理对象

build()方法创建对应的Retrofit之后就是create(Class<T> service)的方法,这里就是生成对应的接口的代理类的方法!!

  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

可以看到,在调用create()方法之后,是通过Proxy生成对应的动态代理!这里就很好说咯,在对应的invoke()的方法中完成具体的请求!

如果Java的动态代理不清楚或者已经忘记了的亲们,这里先简单脑补一下,代理的对应方法最后都会交给InvocationHandler这个类,并通过invoke(Object proxy, Method method, Object... args)的方法去执行相关的逻辑,这里的Method是对应具体方法的信息摘要,反射对象,里面包含了method的名称,参数类型,包括注解那些反正是应有尽有啦!这个args就是具体的方法参数了!

接下来就要注意啦,在创建好了Retrofit之后,在生成动态代理之后,咱们的请求方法还没有构建出来呢!所以呢,接下来肯定就是构建相关的请求方法咯!!

但是明确看到,在返回动态代理之前我们看到这里有一个判断validateEagerly,而且对应的Builder 对外提供了一个设置的方法!

/**
 * When calling {@link #create} on the resulting {@link Retrofit} instance, eagerly validate
 * the configuration of all methods in the supplied interface.
 */
public Builder validateEagerly(boolean validateEagerly) {
  this.validateEagerly = validateEagerly;
  return this;
}

这个方法到底是来做撒的呢?英语好的应该都看明白了!我先绕个关子不讲了!!

直接到代理的invoke()方法中,这里有两个条件判断,第一个是判断返回的类型如果就是Object,那就撒都不搞了,直接执行!

第二个判断如果这个方法是Default的,这个主要是针对java8来说得呢!所以重点还是要跳过到最下面!

ServiceMethod serviceMethod = loadServiceMethod(method);

ServiceMethod的创建

继上面说过的Platform之后,ServiceMethod是我们开始讲解的第二个类了!这里开始创建出对应的ServiceMethod对象,到这个方法里面具体看看!

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

举个例子,比如说我们在LoginApi这个接口里面定义了两个方法:

@POST("users")//https://api.bmob.cn/1/ 注册用户
Call<UserBean> registerUser( @Body UserBean bean);
@GET("getUserInfo")//https://api.bmob.cn/1/用户登陆
Observable<Result<UserBean>> login(@QueryMap Map<String,String> map);

那么当我们执行login()方法的时候,就会创建Retrofit,并且创建这个LoginApi的动态代理,然后调用login()方法,那么这里loadServiceMethod(Method method)中的method方法就是login()这个方法的对象。然后通过ServiceMethod.Builder去构建这个具体的ServiceMethod

//ServiceMethod.Builder的构造方法
public Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();//获取方法的对应注解@retrofit2.http.POST(value=files/{fileName})
  this.parameterTypes = method.getGenericParameterTypes();//获取方法参数的类型
  this.parameterAnnotationsArray = method.getParameterAnnotations();//获取方法参数的注解
}

接下来重点看看ServiceMethod.Builder.builder()的构建过程!这里算是Retrofit里面比较重要的一块了吧,因为它要开始拼接url、确定返回类型、明确CallAdapterresponseConverte

  public ServiceMethod build() {
      //1、获取对应的callAdapter
      callAdapter = createCallAdapter();
      //2、获取对应的response的类型
      responseType = callAdapter.responseType();
      //3、创建response的转换器
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        //4、根据方法的注解(GET POST)开始具体的解析
        parseMethodAnnotation(annotation);
      }
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
          ..........

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
          ........
        //5、解析对应的方法参数注解
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      return new ServiceMethod<>(this);
    }
  • 1、获取对应的callAdapter

      private CallAdapter<?> createCallAdapter() {
            //获取返回值的Type,后面会用到
            Type returnType = method.getGenericReturnType();
            ......
            Annotation[] annotations = method.getAnnotations();
            try {
                      //调用retrofit的方法
              return retrofit.callAdapter(returnType, annotations);
            } catch (RuntimeException e) { // Wide exception range because factories are user code.
              throw methodError(e, "Unable to create call adapter for %s", returnType);
            }
          }
         //callAdapter()方法最终调用nextCallAdapter()来确定具体的callAdapter
        public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
          ....
    
          int start = adapterFactories.indexOf(skipPast) + 1;
          for (int i = start, count = adapterFactories.size(); i < count; i++) {
                    //get是抽象方法,由具体的factory去实现
            CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
            if (adapter != null) {
              return adapter;
            }
          }
         .....
        }
    

前面在说Retrofit的初始化的时候,就说了默认会添加ExecutorCallAdapterFactory,如果我们添加了RxJava支持了添加一个RxJavaCallAdapterFactory的话,那我们这里就有两个CallAdapter了,那么Retrofit是如何明确到底应该使用哪个Adapter的呢?(问题四)相关的答案都在get()的方法中!我们可以看看这两个Factory里面具体的get方法是怎么处理的!

      //ExecutorCallAdapterFactory中
        @Override
      public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        //可以处理Call的返回类型
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }

          @Override public <R> Call<R> adapt(Call<R> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }

      //RxJavaCallAdapterFactory中
        @Override
      public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        Class<?> rawType = getRawType(returnType);
        String canonicalName = rawType.getCanonicalName();
        boolean isSingle = "rx.Single".equals(canonicalName);
        boolean isCompletable = "rx.Completable".equals(canonicalName);
        //可以处理 Observable rx.Single rx.Completable的类型
        if (rawType != Observable.class && !isSingle && !isCompletable) {
          return null;
        }
      ....
      }

答案很是清晰明了啊,不同的adapter在get()中处理不同的逻辑!

  • 2、获取对应的response的类型

这里的response其实就是之前的获取到的returnType在获取到的里面的具体类型,比如说returnType是Call<UserInfo>,那么这里就获取到对应的UserInfo,相关方法封装放在Utils这个工具类中滴!!

  • 3、创建response的转换器

      private Converter<ResponseBody, T> 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);
        }
      }
    
    
        public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
        Type type, Annotation[] annotations) {
      checkNotNull(type, "type == null");
      checkNotNull(annotations, "annotations == null");
    
      int start = converterFactories.indexOf(skipPast) + 1;
      for (int i = start, count = converterFactories.size(); i < count; i++) {
        Converter<ResponseBody, ?> converter =
            converterFactories.get(i).responseBodyConverter(type, annotations, this);
        if (converter != null) {
          //noinspection unchecked
          return (Converter<ResponseBody, T>) converter;
        }
      }
      ....
      }
    

这里其实和前面的创建CallAdapter的原理是一致的!最后调用RetrofitresponseBodyConverter()方法,最后调用nextResponseBodyConverter()的方法,这里这个行为模式就是传说中的责任链模式吧!如果添加了多个,json解析的是要放最后面的,因为它是来者不拒的了!!

  • 4、根据方法的注解(GET POST)开始具体的解析
    到这里就要开始解析方法上的对应注解了!

比如说下面这个Get请求:

@GET("news/before/{date}")
Observable<DailyStories> getBeforeDailyStories(@Path("date") String date);

在通过parseMethodAnnotation()方法之后,会继续执行parseHttpMethodAndPath("GET", ((GET) annotation).value(), false)的方法!

    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()中进行httpMethod、hasBody、relativeUrl、relativeUrlParamNames的赋值!

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      ...
      this.httpMethod = httpMethod;//GET
      this.hasBody = hasBody;//false
      ...
      this.relativeUrl = value;//news/before/{date}
      this.relativeUrlParamNames = parsePathParameters(value);
    }

最后一个parsePathParameters()需要我们着重看一下,到这就要进行相关{date}的替换了!

  static Set<String> parsePathParameters(String path) {
    //static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
    Matcher m = PARAM_URL_REGEX.matcher(path);
    Set<String> patterns = new LinkedHashSet<>();
    while (m.find()) {
      patterns.add(m.group(1));
    }
    return patterns;
  }

因为{date}这一块是需要替换成方法参数里面对应的那个具体值的,这里通过relativeUrlParamNames()的方法,先将{date}取出存入了set集合中!!方便后面根据方法上对应的参数进行替换!!

解析对应的方法参数

接下来就是解析方法对应的参数的注解了:

  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);
  }

这里出现了一个新的类ParameterHandler,这也是第三个需要介绍的类了!

ParameterHandler

ParameterHandler.png

如图所示,ParameterHandler它是一个抽象类,有这么多具体的实现小弟来管理某个具体参数!里面还有一个抽象方法apply()需要每个子类去实现的。这个方法将在后面将具体参数封装到RequestBuilder里面。在上面举例的方法:

  //parameterCount=1,parameterTypes[0]=String.class
   getBeforeDailyStories(@Path("date") String date)

所以最后就是执行parseParameter(0,String,Path),并且返回的就是ParameterHandler的对象!接下来具体看内部是怎么操作的。

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

        if (annotationAction == null) {
          continue;
        }

        if (result != null) {
          throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
        }

        result = annotationAction;
      }

      if (result == null) {
        throw parameterError(p, "No Retrofit annotation found.");
      }

      return result;
    }

这里接着去调用parseParameterAnnotation()的方法,这也是ParameterHandler具体创建的方法!

    private ParameterHandler<?> parseParameterAnnotation(
    int p, Type type, Annotation[] annotations, Annotation annotation) {
      ...

      } else if (annotation instanceof Path) {
      ...
        gotPath = true;

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

        Converter<?, String> converter = retrofit.stringConverter(type, annotations);
        //创建出对应的PathParameterHandler!!
        return new ParameterHandler.Path<>(name, converter, path.encoded());

      } .......

      return null; // Not a Retrofit annotation.
    }

这里会根据不同的类型创建不同的Convert,比如说解析Path就是使用StringConver,并且会先调用validatePathName()的方法去判断之前的Set集合里面是否有这个值,如果有,那么就创建出一个ParameterHandler.Path的对象!
同理解析Body的时候就会去调用nextRequestBodyConverter()的方法最终确认对应的Convert,就这样,最后创建出了ParameterHandler.Body这个具体的ParameterHandler对象!并且相关方法的参数的注解也解析出来并封装到了parameterHandlers数组中!

  ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

到了这里,ServiceMethod的初始化完成,那么每次都去辛辛苦苦的构建这些注解和参数是不是太累了?!所以必须把它缓存起来咯!这里也是上面提出的那个validateEagerlyeagerlyValidateMethods()问题的答案:如果我们需要尽快构建出每个方法的ServiceMethod,那么就将validateEagerly设置为true就好了!


第二部分 HTTP请求 响应 转换

经过上面一系列的准备工作,接下来就是开始相关的网络请求了!回到Retrofit的代理方法中:

 //上面已经创建好对应的ServiceMethod了!
ServiceMethod serviceMethod = loadServiceMethod(method);
//初始化OkHttpCall 
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//执行具体的call
return serviceMethod.callAdapter.adapt(okHttpCall);

OkHttpCall

没有记错的话,OkHttpCall是我们要介绍的第四个对象了!也是比较重要的一个对象了,OkHttpCall 实现了 Call接口,内部持有okhttp3.Call的引用,所以可以理解为它是OkHttpCall的代理对象!

OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);

这里构建出一个具体的OkHttpCall的对象!然后调用了serviceMethod.callAdapter.adapt(okHttpCall)这个方法,接下来着重分析这个方法做了些什么操作!
adapt()CallAdapter里面的抽象方法,由具体的子类实现!如果我们返回的是Call类型的,那么由上面第一部分分析,ServiceMethod这里就是是用的ExecutorCallAdapterFactory!那么到ExecutorCallAdapterFactory中看看具体的实现逻辑!!

  @Override 
  public <R> Call<R> adapt(Call<R> call) {
      return new ExecutorCallbackCall<>(callbackExecutor, call);
  }       

这里又返回了一个ExecutorCallbackCall的对象!这里的callbackExecutor就是在讲初始化Platform创建的!
当我们调用具体的方法时:

login.enqueue(new Callback<UserBean>() {
        @Override
        public void onResponse(Call<UserBean> call, Response<UserBean> response) {
            
        }

        @Override
        public void onFailure(Call<UserBean> call, Throwable t) {     

        }
    });

其实就是调用ExecutorCallbackCall里面的对应方法咯!

 @Override 
 public void enqueue(final Callback<T> callback) {
  if (callback == null) throw new NullPointerException("callback == null");

  delegate.enqueue(new Callback<T>() {
    @Override public void onResponse(Call<T> call, final Response<T> response) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          if (delegate.isCanceled()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
          } else {
            callback.onResponse(ExecutorCallbackCall.this, response);
          }
        }
      });
    }

    @Override public void onFailure(Call<T> call, final Throwable t) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });
}

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

  @Override public void execute(Runnable r) {
    handler.post(r);
  }
}

通过上面的方法就可以完全明白为什么enqueue的方法都是在主线程上的了!!

这里的delegate就是之前传入的OkHttpCall对象,所以这里又会去执行OkHttpCall里面的enqueue()方法,绕了半天,终于又回到了OkHttpCall里面了!

  @Override 
public void enqueue(final Callback<T> callback) {
    ....
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;

      call = rawCall;
      failure = creationFailure;
      if (call == null && failure == null) {
        try {
          //如果call没有创建那么就去创建!
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }

    ....

    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();
        }
      }
    });
}

这个方法有点儿长,主要是判断有木有创建okhttp3.Call,没有就去创建,创建了就调用call的call.enqueue()方法,最后再将结果通过传入的Callback回调出去!

RequestBuilder

先说okhttp3.Call的创建:

call = rawCall = createRawCall();

这里调用了OkHttpCall里面的createRawCall()方法:

  private okhttp3.Call createRawCall() throws IOException {
    //首先创建出okhttp3.Request 
    Request request = serviceMethod.toRequest(args);
    //通过request构建 okhttp3.Call
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

那么从这里开始,这些任务又回到了ServiceMethod这个类中了!所以说ServiceMethod完全服务于Http请求响应的相关过程!

    /** Builds an HTTP request from method arguments. */
  Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

它构建出一个RequestBuilder的类,这也是第五个需要讲解的类了!看名字都知道它就是用来构建RequestBuilder啦!,构建出Builder之后,注意这次是带上具体的参数过来的,所以它会进行参数的封装,构建出最终要去请求的url!!之前有说过对应的每个参数注解已经封装到ParameterHandler这个类中了,这里就需要遍历parameterHandlers这个数组,完成对每一个参数的具体赋值,赋值其实也很简单,就是依次调用各个ParameterHandlerapply(requestBuilder, arg)方法,apply()方法其实就是调用之前构建好的Convert将对应的参数(arg)解析成Request里面具体需要的对象!里面StringConvert居多!比如之前说到的@Body的情况(第一部分的结尾)!,因为Body你也可以传入一个Bean对象,所以不一定使用的是StringConvert,这里它会通过nextRequestBodyConverter()遍历寻找合适Convert。

Convert.png

比如说调用了GsonRequestBodyConverter中的convert方法完成相关解析:

      @Override 
      public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
      }

接着就是调用requestBuilder.build()的方法了!

Request build() {
            //1.构建HttpUrl
            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.
              url = baseUrl.resolve(relativeUrl);
              if (url == null) {
                throw new IllegalArgumentException(
                    "Malformed URL. Base: " + baseUrl + ", Relative: " + relativeUrl);
              }
            }
            2.构建RequestBody
            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();
          }

到这里Request终于是构建好了!接下来是真正的去创建okhttp3.Call了!

okhttp3.Call call = serviceMethod.callFactory.newCall(request);

这里其实最终使用的是Retrofit里面构建的okhttp3.Call.Factory

okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

Response

最后终于到结果的位置了,这个Response也是我们要介绍的第六个对象了!它算是okhttp.Response的一个装饰类吧!也是最后返回给调用者使用的类!

  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;
    }
  }

无论是同步或者异步的方法,最后总会通过parseResponse()的方法将okhttp3.Response包装为Response对象返回!!而具体的解析又会交给ServiceMethod里面的的toResponse()去处理!!

    T toResponse(ResponseBody body) throws IOException {
        return responseConverter.convert(body);
      }

其实就是调用之前确认好的responseConverter去解析对应的Body!
到这里,http请求完成,结果也被封装为指定的对象返回了!

总结

Retrofit.png

1、Call(接口):向服务器发送请求并返回响应的调用;
2、CallAdapter(接口):Call的适配器,将Call适配为不同的类型返回(Call、Observable);
3、CallBack(接口):顾名思义Call的回调,Call执行时的回调;
4、Converter(接口):数据转换器,将一个对象转化另外一个对象;
5、CallAdapter.Factory(接口):CallAdapter的工厂,通过get()方法获取CallAdapter,使用adapt()执行对应的Call请求;
6、Converter.Factory(抽象类) : 数据转换器Converter的工厂;

  • responseBodyConverter:将ResponseBody转换为具体的对象。
  • requestBodyConverter : 将对应的BodyPartPartMap注解转换为RequestBody(OkHttp3),以便http请求的时候使用。
  • StringConverter:将FieldFieldMap 值,HeaderPathQuery,和QueryMap值转化为String,以便http请求的时候使用。

7、ParameterHandler : 方法参数的处理类;

8、ServiceMethod :请求方法的生成处理类,用于确定CallAdapterResponseConverter,生成具体的请求Request,解析对应的Response数据,算是一个灰常重要的类了;
9、Platform:确认不同运行环境的类;
10、OkHttpCall :实现Call接口,是okhttp3.Call的代理类,获取传入的Call,通过Retrofit.callFactory执行Call请求,获取数据并使用ResponseConverter进行解析;

再回到之前说的那些问题上:
1、Retrofit是使用注解确定对应的请求方式和参数的,那么具体的url是怎么产生出来的的呢?
(ServiceMethod里面的相关处理)
2、我们定义的是一个接口,那么Retrofit又是怎么生成对应的实现类的呢?
(动态代理)
3、网络请求V2.0开始统一使用OkHttp了,那么异步回调到主线程是如何实现的?
(MainThreadExecutor)
4、同一个方法,支持Call<T>的返回类型,又可以支持Observable<T>
的返回类型,这个又是如何实现的?
(确定对应CallAdapter!)
5、同一个方法,支持不同的转换(Gson、Jackson、Moshi、FastJson等等),这个又是如何实现的呢?
(确定对应的Convert!)

搞了这么久,学习到什么呢?从一开始的一脸懵逼到最后的暗自窃喜,这也算是一种进步吧!其中不得不提的是各种设计模式的使用,模块间解耦和扩展的思想!创建型的抽象工厂模式、Builder模式;结构性的代理模式、adapter模式、装饰者模式;行为性的责任链模式等等。。

---- Edit By Joe ----

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容