美文网首页
框架源码分析-retrofit

框架源码分析-retrofit

作者: twinsnan | 来源:发表于2016-11-16 20:07 被阅读0次

    使用

    retrofit是最近一款比较火的第三方网络请求框架,使用注解、反射、代理模式等方式构造了整体的框架。
    一、retrofit的使用
    首先来看一下如何使用retrofit:
    1、首先通过构造器模式创建了一个Builder对象,然后传入url地址,添加了Converter工厂,添加了RxJava的适配器工厂,通过build创建了一个Retrofit对象
    2、通过retrofit对象,传入我们一个通过注解方式写的网络请求的接口,里面有我们写的网络请求的方法。然后返回一个Api的代理。retrofit通过代理模式,将注解后的内容解析成我们要网络请求传递的参数和数据,然后封装成一个请求的代理对象。
    3、最后,调用代理对象的方法。由于retrofit可以非常完美的和Rxjava相结合,所以从下面的代码可以看出,api代理请求以后被在主线程中新建的Action1订阅,如果有数据,刷新列表。

    这是RxJava的调用方式

     Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://www.google.com")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
            Api api = retrofit.create(Api.class);
            api.rxBenefits(20, count)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<BaseModel<ArrayList<Benefit>>>() {
                        @Override
                        public void call(BaseModel<ArrayList<Benefit>> model) {
                                              
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
      
                        }
                    })
            ;
    

    这是普通的调用方式

     Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://www.google.com")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            Api api = retrofit.create(Api.class);
            Call<BaseModel<ArrayList<Benefit>>> call = api.defaultBenefits(20, count);
            call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
                             @Override
                             public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {
                                                    }
                             @Override
                             public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
                         }
                  }
            );
        }
    

    retrofit主线分析

    由于需要在创建Builder时传入平台的信息。所以先来看一下platform,如果在android平台,那么返回Android();如果在Java8平台,那么返回Java8(); 但是还有一个IOS?????????如果都不是,返回一个新的Platform对象。

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

    看一下Plaform里面有什么,可以看到有Java8,Android,IOS内部类,这些内部类都是继承自Platform类的。


    image.png

    由于用在Android平台,所以我们只看Android中有些什么,有一个线程池内部内,运行在主线程上。可以获得一个defaultCallAdapterFactory,将线程池对象传了进去。这个等到以后会用到,先不分析这个,只要知道Platform可以拿到线程池和CallAdapterFactory。

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

    这个分析完以后,我们来看retrofit的建造者内部类。

      public static final class Builder {
        // 上面分析的Platform
        private Platform platform;
        // 目前只支持okhttp,获取okhttp的工厂类
        private okhttp3.Call.Factory callFactory;
        // 我们设置的Url
        private HttpUrl baseUrl;
        // 一个converterFactory的List,主要用于将请求内容转化
        private List<Converter.Factory> converterFactories = new ArrayList<>();
        // 用于包装call的工厂的list
        private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
        // 我们穿进去的线程池
        private Executor callbackExecutor;
        // 不知道。。。
        private boolean validateEagerly;
        Builder(Platform platform) {
        // 创建Builder时,需要传入平台的信息
          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.
        // 添加一个内置的converter的工厂
          converterFactories.add(new BuiltInConverters());
        }
        public Builder() {
          this(Platform.get());
        }
     
        public Builder client(OkHttpClient client) {
          return callFactory(checkNotNull(client, "client == null"));
        }
    
        public Builder callFactory(okhttp3.Call.Factory factory) {
          this.callFactory = checkNotNull(factory, "factory == null");
          return this;
        }
    
        public Builder baseUrl(String baseUrl) {
          checkNotNull(baseUrl, "baseUrl == null");
          HttpUrl httpUrl = HttpUrl.parse(baseUrl);
          if (httpUrl == null) {
            throw new IllegalArgumentException("Illegal URL: " + baseUrl);
          }
          return baseUrl(httpUrl);
        }
           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;
        }
        /** Add converter factory for serialization and deserialization of objects. */
        public Builder addConverterFactory(Converter.Factory factory) {
          converterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    
        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    
        public Builder callbackExecutor(Executor executor) {
          this.callbackExecutor = checkNotNull(executor, "executor == null");
          return this;
        }
       
        public Builder validateEagerly(boolean validateEagerly) {
          this.validateEagerly = validateEagerly;
          return this;
        }
        
        public Retrofit build() {
        // 判断url是否为空
          if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
          }
        // 看是否有传入一个callFactory,如果没有传入,那么就创建一个新的
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {
            callFactory = new OkHttpClient();
          }
        // 看是否有传入线程池,如果没有传入,创建一个新的,这里看到我们上满分析的Platform类,创建一个运行在主线程的callbackExecutor
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
        // 新建calladapter的List,添加platform中默认的factory,这个factory也是我们上面分析到过的,但是具体功能等到下面来分析。主要用于将请求适配成我们需要的Call请求封装对象
          // Make a defensive copy of the adapters and add the default Call adapter.
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
        // 将构造器中的convertfactory List放进去,这个主要用于将请求转换为我们需要的格式
    
          // Make a defensive copy of the converters.
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
        // 创建retrofit对象返回
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);
        }
      }
    

    分析完构造器,我们再来看一下通过代理模式创建请求接口的对象的代码。源码注释中已经写得比较明白了这个方法的具体作用

      @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
      public <T> T create(final Class<T> service) {
        // 首先接茬service是否为一个符合规范的interface,如果不是接口,或者实现了其他接口,则抛出异常
        Utils.validateServiceInterface(service);
        if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
        // 动态代理,这个retrofit比较关键的部分
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
        // 获取Platform对象
              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.
        // 得到目标方法所在类对应的Class对象,如果是Object类,则调用一般的反射
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
        // 在Android凭条,这个都是false
                if (platform.isDefaultMethod(method)) {
                  return platform.invokeDefaultMethod(method, service, proxy, args);
                }
        // 通过反射获得ServiceMethod对象
                ServiceMethod serviceMethod = loadServiceMethod(method);
        // 获得一个OkHttpCall
                OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
        // 调用CallAdapter中的adapt方法,将okHttpCall转换为我们需要的类型
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    接下来我们对上面三个标黄的方法逐个分析
    首先来卡ServiceMethod类,下面这个是Retrofit中的方法。

    private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
    

    serviceMethodCache是一个非常重要的map,用于保存代理后的方法。
    loadServiceMethod也是Retrofit中的方法,首先判断是否已经存在,如果不存在则创建,创建后加入到map中。

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

    分析new ServiceMethod.Builder(this, method).build();
    在ServiceMethod类中:

        public Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
        // 获取方法上的注解
          this.methodAnnotations = method.getAnnotations();
        // 方法参数类型的数组
          this.parameterTypes = method.getGenericParameterTypes();
        // 获取参数的注解的数组
          this.parameterAnnotationsArray = method.getParameterAnnotations();
        }
    

    (注:getgenericparametertypes)

    public type[] getgenericparametertypes()
    按照声明顺序返回 type 对象的数组,这些对象描述了此 method 对象所表示的方法的形参类型的。如果底层方法不带参数,则返回长度为 0 的数组。
    如果形参类型是参数化类型,则为其返回的 type 对象必须实际反映源代码中使用的实际类型参数。
    如果形参类型是类型变量或参数化类型,则创建它。否则将解析它。
    返回:
    按照声明顺序返回表示底层方法的形参类型的 type 对象数组
    

    建造者构建

        public ServiceMethod build() {
        // 新建callAdapter
          callAdapter = createCallAdapter();
        // ...
          responseType = callAdapter.responseType();
          if (responseType == Response.class || responseType == okhttp3.Response.class) {
            throw methodError("'"
                + Utils.getRawType(responseType).getName()
                + "' is not a valid response body type. Did you mean ResponseBody?");
          }
        // 新建responseConverter
          responseConverter = createResponseConverter();
          for (Annotation annotation : methodAnnotations) {
        // 解析方法的注解
            parseMethodAnnotation(annotation);
          }
          if (httpMethod == null) {
            throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
          }
          if (!hasBody) {
            if (isMultipart) {
              throw methodError(
                  "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
            }
            if (isFormEncoded) {
              throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
                  + "request body (e.g., @POST).");
            }
          }
          int parameterCount = parameterAnnotationsArray.length;
          parameterHandlers = new ParameterHandler<?>[parameterCount];
          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);
          }
          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);
        }
        private CallAdapter<?> createCallAdapter() {
          Type returnType = method.getGenericReturnType();
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
          Annotation[] annotations = method.getAnnotations();
          try {
            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中调用的是Retrofit中的代码

      /**
       * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
       * #callAdapterFactories() factories} except {@code skipPast}.
       *
       * @throws IllegalArgumentException if no call adapter available for {@code type}.
       */
      public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
        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;
          }
        }
    

    如果是默认的,则调用ExecutorCallAdapterFactory中的get方法,返回的Call最主要的是adapt。adapt方法将一个Call对象传入。我们来看一下传入后返回的是什么
    记得创建Retrofit对象时如果不传入CallAdaperFactory,那么会新建ExecutorCallAdapterFactory,新建时将主线程的Executor传入。adapt后的ExecutorCallbackCall中enqueue非常重要,其将在子线程中请求的返回值发布到主线程中,然后是success和fail的方法回调。

    @Override
      public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        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);
          }
        };
      }
      static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;
        final Call<T> delegate;
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
          this.callbackExecutor = callbackExecutor;
          this.delegate = delegate;
        }
        @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(final 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(call, new IOException("Canceled"));
                  } else {
                    callback.onResponse(call, response);
                  }
                }
              });
            }
            @Override public void onFailure(final Call<T> call, final Throwable t) {
              callbackExecutor.execute(new Runnable() {
                @Override public void run() {
                  callback.onFailure(call, t);
                }
              });
            }
          });
        }
    

    最后我们来看一下请求前和请求后对数据进行封装和解析的过程。
    在Retrofit进行创建的时候,我们是可以传入一个ConvertorFactory对象的,如最上面的示例。

    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://gank.io/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .build();
    

    那么我们来看一下GsonConverterFactory里面有什么

    /**
     * A {@linkplain Converter.Factory converter} which uses Gson for JSON.
     * <p>
     * Because Gson is so flexible in the types it supports, this converter assumes that it can handle
     * all types. If you are mixing JSON serialization with something else (such as protocol buffers),
     * you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance}
     * last to allow the other converters a chance to see their types.
     */
    public final class GsonConverterFactory extends Converter.Factory {
      /**
       * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
       * decoding from JSON (when no charset is specified by a header) will use UTF-8.
       */
      public static GsonConverterFactory create() {
        return create(new Gson());
      }
      /**
       * Create an instance using {@code gson} for conversion. Encoding to JSON and
       * decoding from JSON (when no charset is specified by a header) will use UTF-8.
       */
      public static GsonConverterFactory create(Gson gson) {
        return new GsonConverterFactory(gson);
      }
      private final Gson gson;
      private GsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        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);
      }
    }
    

    从源码中可以看到,该类继承自 Converter.Factory,最主要的是responseBodyConverter和requestBodyConverter这两个方法。这两个方法获得请求和相应的转换类,再进去看下转换类里面的内容。发现是一些Gson转换的东西。

    final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
      private final Gson gson;
      private final TypeAdapter<T> adapter;
      GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
      }
      @Override public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        try {
          return adapter.read(jsonReader);
        } finally {
          value.close();
        }
      }
    }
    

    在ServiceMethod创建时获得了ResponseConverter,该Conveter是从retrofit中获得的

    responseConverter = createResponseConverter();
    

    在ServiceMethod的toResponse方法中使用了responseConveter.convert方法。(toResponse方法在OkHttpCall执行请求结束后的parseResponse中调用)

      /** Builds a method return value from an HTTP response body. */
      T toResponse(ResponseBody body) throws IOException {
        return responseConverter.convert(body);
      }
    

    而requestConverter方法则在ServiceMethod中的parseParameterAnnotation方法中调用,获取了retrofit中的Converter对象。

     Converter<?, RequestBody> converter =
                    retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
    

    到这里,Retrofit的大致框架已经分析完了。如果有机会,RxjavaCallAdapter这个比较重要的部分还没有分析,会再去详细的分析。

    源码

    github上的源码:
    https://github.com/square/retrofit

    相关文章

      网友评论

          本文标题:框架源码分析-retrofit

          本文链接:https://www.haomeiwen.com/subject/kqirpttx.html