Retrofit2.0源码解析

8 篇文章 0 订阅
3 篇文章 0 订阅
引用

Retrofit是Square生产的一款用于网络请求的框架,遵循RestApi风格,以其简单的网络配置与自定义设置,支持RxJava,自定义数据转换器等,Github上的start数已经有将近3w,而且目前一直在维护,内部网络请求采用okhttp来进行网络访问,这一系列的特性使其成为网络请求框架的新宠儿

既然Retrofit如此火爆,那么自然是因为其良好的设计架构,完美的项目解耦,其实Retrofit最大的优点就是他使用了多种设计模式来进行解耦,比如 CallAdapterFactoryConvertAdapterFactory 来根据用户传入的不同类型的适配器对数据进行梳理,用户没必要关心数据的变化,一次配置,终身享用。好了,还是直接来根据代码探究Retrofit的优美,本篇文章是基于Retrofit2.0版本来进行代码跟踪,好了,开车。

  • 创建一个全局Retrofit实体类
   Retrofit retrofit = new Retrofit.Builder()// 构建者模式填充参数
                .baseUrl("http://127.0.0.1:8080") // 必填 http的主机名+端口号 *以/结尾
                .client(new OkHttpClient()) // 选填,可定制OkHttpClient 比如添加相应的拦截器等
                .addConverterFactory(GsonConverterFactory.create()) // 添加response中body的数据转换工厂
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 添加 call(okhttp中请求的执行体) 的转换工厂,这里就转换成了Observable
                .build();

以上就是Retrofit实体对象的创建,一般创建为全局单例,个人喜欢放在静态代码块中,上面提到的OkHttpClient 一般都是自己定制,创建拦截器,添加Token到Headers等,OkHttpClient 也最好写成全局唯一,因为每一个OkHttpClient 内部维护的网络请求线程池以及connnection 连接池都是维护在一个OkHttpClient 实体对象中的,一旦每次请求去创建就会丧失OkHttpClient 的性能,OkHttp 的源码解析可以看我的上篇OkHttp源码解析
接下来我们看一下Retrofit的源码,看一下Retrofit的都有哪些参数,以及我们传递的这些参数用来做什么呢?

  private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); // 由于缓存每个api生成的方法

  final okhttp3.Call.Factory callFactory; // 执行器工厂 这里代表OkHttpClient
  final HttpUrl baseUrl; // 主机名+端口号 
  final List<Converter.Factory> converterFactories; // 数据转换器工厂集合
  final List<CallAdapter.Factory> adapterFactories; // 执行器适配工厂集合
  final @Nullable Executor callbackExecutor; // 回调执行器
  • 创建基于注解的RestApi接口:
public interface ApiService {
    // retrofit的post请求
    @POST("/app/v1/user/login")
    Call<HttpResult<UserVo>> loginPost(@Body Map<String, Object> params);
    }

所有的api都是以注解的形式卸载这个接口中,该接口用来生成上面提到的缓存的MethodServcie;

  • 构建Api的生产接口
        apiService = retrofit.create(ApiService.class);
  • API的调用
 Map<String,Object> map = new HashMap<>();
        map.put("name","lu");
        map.put("password","123");
        apiService.loginPost(map).enqueue(new Callback<HttpResult<UserVo>>() {
            @Override
            public void onResponse(Call<HttpResult<UserVo>> call, Response<HttpResult<UserVo>> response) {
                Log.d(TAG, "onResponse: "+success);
            }

            @Override
            public void onFailure(Call<HttpResult<UserVo>> call, Throwable t) {
                Log.d(TAG, "onFailure: "+fail);
            }
        });

以上就是一整套Retrofit的网络请求。

  • 分析Retrofit源码创建过程:
@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);   // 1.1
    }
    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<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);// 1.2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);//1.3
            return serviceMethod.callAdapter.adapt(okHttpCall);//1.4
          }
        });
  }
  • 1.1 该段代码会在Retrofit第一次cretae的时候调用,点进去:
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get(); // 获取当前的PlatForm #1.1.1
// 遍历接口中所有Method
    for (Method method : service.getDeclaredMethods()) { 
          //判断是不是default方法,jdk7以后接口中可以编写方法的实现,但是必须在方法前面设置一个关键字`default'
      if (!platform.isDefaultMethod(method)) { 
        loadServiceMethod(method); #1.1.2
      }
    }
  }
  • 1.1.1 获取当前Platform(平台),该类包含两个实现类:
    Platform实现类
    因为Retrofit这个支持Android同时也支持Java所以会根据Class的包名判断是当前平台环境:
  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) {
    }
    return new Platform();
  }

而我们只来卡一下Android这个Platform的实现类,这个类总共十几行:

  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
    // 构建一个用来将响应事件发送到Main线程
      return new MainThreadExecutor();  
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      // 返回一个默认的Call(执行器)的适配器工厂,就是用来将执行结果转换成你想要的返回对象,比如,你想要Observer<Object> 等
      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);
      }
    }
  }
  • 1.1.2 加载接口中的非default方法,构建一个ServiceMethod对象,以Method为Key,该对象队value添加到到文章开始讲的方法集合缓存起来,:

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

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
      // 传入Retrofit实例和Method到MethodBuild=对象构建一个ServiceMethod,该对象将会包含Retrofit所有数据,以后就是又来对象完成数据请求以及封装
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

好了,再来看一下这个方法的动态代理里面的东西:

(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)) {//如果该方法是声明为default,则正常调用该方法,
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);// 1.2
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);//1.3
            return serviceMethod.callAdapter.adapt(okHttpCall);//1.4
          }
        });
  • 1.2 从缓存ServiceMethod的方法的集合中根据Method获取该ServiceMethod实例对象。

  • 1.3 根据Method和参数创建一个OkHttpCall 这个和OkHttp中的Call是相同的功能,如果不太清楚查看上篇OkHttp源码分析了解Call的执行流程,其实就是代表一个请求的执行对象。

  • 1.4 前面提到ServiceMethod在构建的时候传入了this(retrofit实例)所有持有Retrofit的所有实例成员,这里调用callAdapter 实例来将call 对象传入,使用构造Retrofit时传入的CallAdapter.Factory对象将该Call对象转换成factory 所需要的返回类型,我们看一下这个CallAdapter.Factory 接口:
public interface CallAdapter<R, T> {

  T adapt(Call<R> call);


  abstract class Factory {

    public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

    protected static Type getParameterUpperBound(int index, ParameterizedType type) {
      return Utils.getParameterUpperBound(index, type);
    }

    protected static Class<?> getRawType(Type type) {
      return Utils.getRawType(type);
    }
  }
}

其实就是讲CallAdapter< R >转换成CallAdapter< T > ,接下来看一下实现该接口的都是那些:
CallAdapter.Factory 实现类

上面在讲Platform说过,默认的CallAdapterFactory 就是 ExectuorCallAdapterFactory,我们只关心他的adapter 方法:

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

创建了一个ExecutorCallbackCall 其中第一个参数其实就是Android那个Platform中的MainThreadExecutor(持有有个主线程的Handler,发送响应是事件到主线程),那来看一下这个类到底做了什么:

static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor; // 回调的Executor
    final Call<T> delegate; // 代理Call 真正的执行Call

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }
    // 发送同步请求
    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "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);
            }
          });
        }
      });
    }
     // 判断该Call是否已经执行
    @Override public boolean isExecuted() {
      return delegate.isExecuted();
    }
     // 发送同步请求
    @Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }
    // 取消该call 就是在okhttp的call池中移除,具体参看我的上篇okhttp源码分析
    @Override public void cancel() {
      delegate.cancel();
    }
  // 判断该Call是否已经取消掉了
    @Override public boolean isCanceled() {
      return delegate.isCanceled();
    }

    @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
    @Override public Call<T> clone() {
      return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
    }

    @Override public Request request() {
      return delegate.request();
    }
  }

走到这里,可以继续点进去,其实真正执行http请求的还是OkHttp。
再看一下Retrofit 创建的时候添加ConvertFatory,这个主要就是用来进行响应结果的数据类型转换,看一下GsonConvertFactory

public final class GsonConverterFactory extends Converter.Factory {

  public static GsonConverterFactory create() {
    return create(new Gson());
  }


  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }

  private final Gson gson;

  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}

没多少代码,其实就是利用Gson将response转换成实体对象,自己也可以写一个,只要实现Converter<F, T> 这个接口,Retrofit不仅仅只支持gson,还支持其他许多json解析库。以下版本号需要与retrofit版本号保持一致,并且以retrofit官网给出的版本号为准。

  • Gson: compile ‘com.squareup.retrofit2:converter-gson:2.0.1’
  • Jackson: compile ‘com.squareup.retrofit2:converter-jackson:2.0.1’
  • Moshi: compile ‘com.squareup.retrofit2:converter-moshi:2.0.1’
  • Protobuf: compile ‘com.squareup.retrofit2:converter-protobuf:2.0.1’
  • Wire: compile ‘com.squareup.retrofit2:converter-wire:2.0.1’
  • Simple XML: compile ‘com.squareup.retrofit2:converter-simplexml:2.0.1’
  • Scalars (primitives, boxed, and String): compile ‘com.squareup.retrofit2:converter-scalars:2.0.1’

Retrofit这个框架包含了好多设计模式在里面,比如外观、工厂、适配器、构建者、等等,个人只是懂一点皮毛,个人理解而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值