retrofit源码解析

一、简介

retrofit是square开发的一个网络加载库,主要用于Android和Java。Retrofit对OKHttp进行了封装,加入了各种设计模式,注解,反射,使用起来更加方便。

二、使用方法

retrofit的使用大致分为三个部分:定义网络接口、创建retrofit对象、创建网络接口的动态代理、调用网络接口

2.1 定义网络接口

public interface GitHubService {
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

上面的例子中创建了一个GitHubService接口,接口中定义了一个listRepos方法,listRepos一个String类型参数user,返回值是Call>。
同时,listRepos中有很多注解,我们一一分析这些注解:
@GET("users/{user}/repos")表明该方法是一个GET请求,("users/{user}/repos")是网络请求的相对路径,启动{user}是可变部分。
@Path("user")是一个参数注解,表明该参数是用来替换网络请求路径中的{user},总而组成动态变化的路径。

2.2 创建retrofit对象

Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())  //结构化数据和java对象之间的转化
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())  //适配不同平台(JAVA8、Android、RxJava,Guava)
.build();

可以看出这是一个builder模式,用于构建retrofit对象。上面的例子中:
1.设置了baseUrl,用于和接口中的相对地址一起组成完成的网络请求地址;
2.设置了ConverterFactory,用于将OKHttp的call转化为不同平台的call(因为retrofit底层是OKHttp,retrofit的网络请求都是通过调用OKHttp来进行的。同时retrofit还支持在不同平台上使用,因此就需要将OKHttp原生的call换转为不同平台的call,这就是适配器模式);
3.设置了数据转换器,用于将服务器返回的json\xml\protobuf等格式的数据转化为java对象。

2.3 创建网络加载接口的动态代理

GitHubService service = retrofit.create(GitHubService.class);

retrofit.create创建了一个接口的动态代理,每次调用接口的方法,都会执行动态代理的invoke方法,用于执行真正的网络加载逻辑。

2.4 调用网络加载接口

Call> repos = service.listRepos("octocat");
repos.enqueue(new Callback>() {
    @Override
    public void onResponse(Call> call, Response> response) {
            
    }
    @Override
    public void onFailure(Call> call, Throwable t) {

    }
 });

调用接口,返回一个retrofit的call对象,该对象保存网络请求的参数,提供同步、异步加载,内部调用OKHttp的call执行网络通信。

三、retrofit源码概述

retrofit内部使用了很多设计模式(builder模式、适配器模式、工厂模式、装饰模式等),提供了很多注解,使用了动态代理。

3.1 框架流程图

retrofit框架

3.2 初始化和准备

3.2.1retrofit的成员对象

代码位置retrofit2.Retrofit

  private final Map> serviceMethodCache = new ConcurrentHashMap<>();  //缓存method和其解析对象
  final okhttp3.Call.Factory callFactory;   //okHttp工厂
  final HttpUrl baseUrl;
  final List converterFactories;   //数据转换器集合
  final List callAdapterFactories;   //网络适配器工厂集合
  final @Nullable Executor callbackExecutor;   //异步请求结果线程切换器
  final boolean validateEagerly;   //是否提前解析所有method并缓存

retrofit存储着网络请求的基本信息。

3.2.2 retrofit的静态内部类builder与建造者模式

代码位置retrofit2.Retrofit

  public static final class Builder {
    private final Platform platform;   //
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List converterFactories = new ArrayList<>();
    private final List callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    Builder(Platform platform) {
      this.platform = platform;
    }

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

    Builder(Retrofit retrofit) {}

    /**
     * 设置网络请求客户端
     */
    public Builder client(OkHttpClient client) {}

    /**
     * 设置底层网络请求的工厂方法,retrofit底层是OkHttp
     */
    public Builder callFactory(okhttp3.Call.Factory factory) {}

    /**
     * 设置基础的url,比如https://www.jianshu.com/u/9a2d2f05977c 的基础url是https://www.jianshu.com/
     */
    public Builder baseUrl(URL baseUrl) {}

    /**
     * 
     */
    public Builder baseUrl(String baseUrl) {}

    /**
     * 
     */
    public Builder baseUrl(HttpUrl baseUrl) {}

    /**
      * 设置数据转换器的工厂
     */
    public Builder addConverterFactory(Converter.Factory factory) {}

    /**
     * 设置网络适配器工厂
     */
    public Builder addCallAdapterFactory(CallAdapter.Factory factory) {}

    /**
     * 设置回调函数执行器
     */
    public Builder callbackExecutor(Executor executor) {}

    /** Returns a modifiable list of call adapter factories. */
    public List callAdapterFactories() {}

    /** Returns a modifiable list of converter factories. */
    public List converterFactories() {}

    /**
     * 创建retrofit对象
     */
    public Retrofit build() {}
  }

retrofit有一个静态内部类builder,他用于延迟创建retrofit对象。这是一个典型的建造者模式。builder内部的成员变量和retrofit一样,还提供了很多初始化成员变量的方法,这些方法都返回builder对象本身,用于链式编程。

3.2.2 创建网络请求接口的动态代理

代码位置retrofit2.Retrofit

    /**
     * 返回网络请求接口的动态代理
     */
  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  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();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);  //解析接口,返回动态代理
          }
        });
  }

上面的代码使用Proxy.newProxyInstance为接口生成动态代理,每次调用接口,真正执行逻辑的是代理。

3.3 调用网络请求接口

3.3.1 动态代理中的逻辑

代码位置retrofit2.Retrofit

    /**
     * 创建动态代理
     */
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();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);  //解析接口,返回动态代理
          }
        });
  }
    /**
     * 提前解析
     */
  private void eagerlyValidateMethods(Class service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {   //遍历所有method
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);  //从缓存中获取该method对应的methodService(key是method),如果缓存中没有,解析该方法的所有注解,生成serviceMethod,添加缓存
      }
    }
  }
    /**
     * 解析的实际处理方法,首先从缓存中获取,缓存中没有再进行解析(调用ServiceMethod.parseAnnotations),并把缓存结果lru缓存
     */
  ServiceMethod loadServiceMethod(Method method) {  //从缓存中获得ServiceMethod
    ServiceMethod result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method); //先从hua
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);  //解析出来srviceMethod,放入缓存中
      }
    }
    return result;
  }

我们每次调用网络请求接口,都会调用InvocationHandler的invoke方法。invoke方法中调用loadServiceMethod(method)方法解析接口。
loadServiceMethod(method)方法中首先检查缓存,如果该method没有对应的ServiceMethod缓存,则调用ServiceMethod.parseAnnotations解析接口信息,并缓存起来。
代码位置retrofit2.ServiceMethod

abstract class ServiceMethod {
  static  ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);  //调用RequestFactory解析该方法中的注解和参数注解

    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);  //传入参数和注解,生成HttpServiceMethod对象
  }

  abstract @Nullable T invoke(Object[] args);
}

ServiceMethod是一个抽象类,内部有两个方法。static ServiceMethod parseAnnotations(Retrofit retrofit, Method method)方法调用RequestFactory 解析接口,返回HttpServiceMethod对象。
HttpServiceMethod继承了ServiceMethod,实现了invoke方法。
代码位置retrofit2.HttpServiceMethod

  @Override final @Nullable ReturnT invoke(Object[] args) {  //反射方法,将原来的方法转换成httpCall
    Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);  //先生成okhttpcall
    return adapt(call, args);  //然后使用callAdapter生成对应平台的call
  }

invoke方法中先创建了一个OkHttpCall对象,然后使用CallAdapter创建了对象平台的call。

总结:首先从缓存中获取method对应的serviceMethod,如果没有,调用ServiceMethod解析接口,并缓存;然后使用解析到的接口数据,接口参数,指定的工厂方法创建OKHttpCall;最后调用CallAdapter创建对应平台的call。

3.3.2 执行网络请求

从3.3.1小节中我们得知,每次调用接口,执行逻辑的都是代理(代理中解析接口注解,创建OkHttpCall,最后使用CallAdapter创建指定平台的call)。
假设我们设置的CallAdapterFactory是RxJava2CallAdapterFactory,我们看一下RxJava2CallAdapter中的逻辑。
代码位置retrofit2.adapter.rxjava2.RxJava2CallAdapter

  @Override public Object adapt(Call call) {
    Observable> responseObservable = isAsync    //创建RxJava的Observable,对OKHttp的call进行包装
        ? 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 RxJavaPlugins.onAssembly(observable);
  }

RxJava2CallAdapter中的adapter方法创建了一个被观察者,该被观察者对OkHttp的call进行了包装,从而使得retrofit可以支持RxJava。
我们继续看responseObservable。
代码位置retrofit2.adapter.rxjava2.CallEnqueueOnSubscribe

final class CallEnqueueOnSubscribe implements OnSubscribe> {
  private final Call originalCall;

  CallEnqueueOnSubscribe(Call originalCall) {
    this.originalCall = originalCall;
  }

  @Override public void call(Subscriber> subscriber) {  
    // Since Call is a one-shot type, clone it for each new subscriber.
    Call call = originalCall.clone();
    final CallArbiter arbiter = new CallArbiter<>(call, subscriber);
    subscriber.add(arbiter);
    subscriber.setProducer(arbiter);

    call.enqueue(new Callback() {    //调用了OkHttp的enqueue方法执行真正的网络加载。
      @Override public void onResponse(Call call, Response response) {
        arbiter.emitResponse(response);  //发射时间
      }

      @Override public void onFailure(Call call, Throwable t) {
        Exceptions.throwIfFatal(t);
        arbiter.emitError(t);  //发射onError
      }
    });
  }
}

responseObservable的call方法内部调用了OkHttp来执行真正的网络加载。并且根据返回信息反射对应的时间,使RxJava的观察者可以接收事件。

四、总结

retrofit的源码很值得我们学习,其中包括了各种设计模式,反射,动态代理。看完感叹自己要学得还有很多啊。

你可能感兴趣的:(retrofit源码解析)