美文网首页
Retrofit从使用到原理

Retrofit从使用到原理

作者: 帝王鲨kingcp | 来源:发表于2018-12-12 11:24 被阅读0次

    使用Retrofit

    网上使用Retrofit的好文章很多,我也就不重复造轮子。给大家推荐一些文章:看了这些文章你如真的理解Retrofit,你会发现其实下面实现的功能,其实很多是对OkHttp的操作,因为Retrofit底层请求使用的就是OkHttp,Retrofit的真正的作用就是你可以用注解接口的方式请求。当然Retrofit也做了很多细节处理,做到了类型安全等。

    解析Retrofit的核心结构

    一般使用Retrofit会分下面几步
    • Retrofit会把http api请求用java接口的方式呈现。
    public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
    • Retrofit会通过动态代理生成GitHubService。
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .build();
    
    GitHubService service = retrofit.create(GitHubService.class);
    
    • 通过生成的GitHubService,创建不同的call的http请求。通过enqueue方法,或者execute方法,让其异步或者同步执行。
    Call<List<Repo>> repos = service.listRepos("octocat");
    
    repos.enqueue(new Callback<List<Repo>>() {
                @Override
                public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
                    
                }
    
                @Override
                public void onFailure(Call<List<Repo>> call, Throwable t) {
    
                }
            });
    

    核心原理分析

    通过Retrofit.create()创建出Service interface的实例,从而使得Service中配置的方法变得可用,这是Retrofit代码结构的核心。跟进retrofit.create()的方法,首先检查service是不是接口并且继承接口,让后看看是否需要提前创建方法,放入serviceMethodCache中,默认不需要。最后就是重点动态代理,创建动态对象。动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。是因为所有被代理执行的方法,都是通过在InvocationHandler中的invoke方法调用的,所以我们只要在invoke方法中统一处理,就可以对所有被代理的方法进行相同的操作了。具体动态代理相关内容可以看这篇文章:java动态代理实现与原理

      public <T> T create(final Class<T> service) {
        //检查service,是不是接口,是否继承接口。要求service是接口且不继承其他接口
        Utils.validateServiceInterface(service);
       //默认为false,判断是否需要提前loadServiceMethod(method);
        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 {
                //如果方法来自object或者platform,那就正常调用
                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);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.adapt(okHttpCall);
              }
            });
      }
    

    下面是三行代码就是整个create方法的核心,创建一个实现service接口类的实例。

    ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.adapt(okHttpCall);
    
    第一行:ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);

    ServiceMethod将一个接口方法适配成为一个HTTP请求,读取网络请求接口里的方法,并根据前面配置好的属性配置serviceMethod对象。loadServiceMethod方法的作用就是将接口注解解析,并存到serviceMethodCache中。下面的代码逻辑:如果serviceMethodCache中存在,就直接返回结果。然后同步以下内容操作:再次从serviceMethodCache中尝试获取,如果还是没有,就自己创建,然后将创建的好的对象放入serviceMechodCache中。

      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,就在ServiceMethod.Builder<>(this, method).build()中实现,下面就是源码,主要作用就是负责读取interface中原方法的信息:返回值类型,请求方法注解,参数类型,参数注解。同时也创建callAdapter,responseConverter等后续请求和返回数据转换会用到的对象,同时调用parseMethodAnnotation,parseParameter方法将注解的方法和参数组装好。然后返回ServiceMethod对象。

        public ServiceMethod build() {
         //创建CallAdapter,默认创建ExecutorCallAdapterFactory
          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 = 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);
    
    第二行:OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);

    OkHttpCall的创建:下面这行代码主要负责将ServiceMethod封装近一个retrofit2.call对象中。在使用enqueue()方法中,利用ServiceMethod中包含的信息创建一个okhttp3.Call对象,并调用okhttp3.Call对象来进行网络请求的发起,然后对结果进行处理。也就是说retrofit2.Call包装了一个okhttp3.Call,所有的工作都由okhttp3.Call来进行处理。一句话就是变成okhttpcall,进行真正的网络请求。如果是不能再主线程中执行的请求,例如下面的enqueue方法:
    enqueue方式中明显的看到用createRawCall方法创建出一个okhttp3.call的方法,然后让真实去做请求的okhttp3.call去做enqueue方法。

      @Override public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");
    
        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 {
              call = rawCall = createRawCall();
            } catch (Throwable t) {
              throwIfFatal(t);
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
    
        if (canceled) {
          call.cancel();
        }
    
        call.enqueue(new okhttp3.Callback() {
          @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
    
            try {
              callback.onResponse(OkHttpCall.this, response);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          @Override public void onFailure(okhttp3.Call call, IOException e) {
            callFailure(e);
          }
    
          private void callFailure(Throwable e) {
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    

    createRawCall做了什么?erviceMethod.toCall(args)将解析注解得到的请求方法,请求参数构建成一个okhttp3.call。具体如何构建,我也没有仔细看过。

    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = serviceMethod.toCall(args);
        if (call == null) {
          throw new NullPointerException("Call.Factory returned null.");
        }
        return call;
      }
    
    第三行:serviceMethod.adapt(okHttpCall)

    adapt()方法就是把okHttpCall对象进行转化,生成一个新的retrofit2.Call对象,这样就变回去了,上一步将retrofit2.call对象变成OkHttpCall3.call去进行网络请求。其实这个方法也可以生成别的对象,如果Retrofit中添加addCallAdapterFactory(RxJava2CallAdapterFactory.create()),Rxjava的Obervable同样也可以被创建。

      T adapt(Call<R> call) {
        return callAdapter.adapt(call);
      }
    

    callAdapter是网络请求适配器,将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式,通过createCallAdapter()产生,我们一步一步的跟进,调用retrofit.callAdapter(returnType, annotations);

        private CallAdapter<T, R> 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 {
            //noinspection unchecked
            return (CallAdapter<T, R>) 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);
          }
        }
    

    然后再调用nextCallAdapter(null, returnType, annotations)

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

    在nextCallAdapter()方法中,调用CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this)来找到adapter,查找callAdapterFactory,在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。
    在Retrofit.build()的中会给callAdapterFactories添加CallAdapterFactorie,如果没有添加RxJavaCallAdapter之类就按默认提供的CallAdapterFactory。

          List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
          callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
      CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
        if (callbackExecutor != null) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
        return DefaultCallAdapterFactory.INSTANCE;
      }
    
      boolean isDefaultMethod(Method method) {
        return false;
      }
    
      @Nullable Object invokeDefaultMethod(Method method, Class<?> declaringClass, Object object,
          @Nullable Object... args) throws Throwable {
        throw new UnsupportedOperationException();
      }
    

    我们知道默认的callAdapter来自ExecutorCallAdapterFactory,找到adapt()方法,从okhttp.call适配成retrofit.call。

     @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public Call<Object> adapt(Call<Object> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    

    进入ExecutorCallbackCal中,delegate就是一个okhttp3.call,有我们的生成的okhttpCall传入。印证了我们之前收到,无论转化成Retrofit2.call还是RxJava的observable,最后正常的进行网络请求的还是okhttp3.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) {
          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);
                }
              });
            }
          });
        }
       ......
    }
    

    enqueue方法具有切换功能原因就在这里,new Handler(Looper.getMainLooper())

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

    Retrofit的总体逻辑就是上面内容,下面有一篇介绍的比较详细
    Android:手把手带你 深入读懂 Retrofit 2.0 源码

    三件套缺一不可:

    OkHttp从使用到原理
    Retrofit从使用到原理
    RxJava从使用到原理

    相关文章

      网友评论

          本文标题:Retrofit从使用到原理

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