面试必问框架之Retrofit源码解析

retrofit是目前Android移动端领域最火的框架,相比我们之前使用的HttpClient 、XUtils、Volley等拥有非常方便的API、丰富的注解,帮助开发者轻松实现网络请求,并且遵从RESTFUL接口的场景。
众所周知这个框架是对OKhttp的封装,意思就是说它本身不具备网络请求的功能,它只是把我们需要请求的URL、参数以及请求类型封装起来,然后告诉底层的OkHttp发送请求,并把请求结果返回回来。
使用发送一个HTTP请求只需要三步:

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

Retrofit retrofit = new Retrofit.Builder()
	.client(okHttpClient)
    .baseUrl("https://api.github.com/")
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
GitHubService service = retrofit.create(GitHubService.class);
Call<List<Repo>> repos = service.listRepos("octocat");

上面就是我们基础的发送一个网络请求需要的步骤,定义一个接口里面定义我们需要发送的网络请求url 以及参数和请求方式。 其次就是 new Retrofit.Builder().build() 使用建造者模式创建一个Retrofit实例,调用retrofit.create(GitHubService.class) 得到一个接口实例,到此我们可以调用我们在接口定义的每个服务接口。到这里我们是不是感觉很神奇。接口上定义的@GET("users/{user}/repos")@Path("user") String userCall<List<Repo>> 这些东西是怎么加入到一个网络请求的呢? 待着这些疑问我们看看 retrofit.create方法。在这之前我们先看看Retrofit.Builder().build

    public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
	  //this.callFactory 其实就是一个OkHttpClient 如果我们不需要给OkHttpClient 自定义一些超时时间 和 拦截器我们不需要创建他可以自己创建
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
	  // 注释1 
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
		// RxJava2CallAdapterFactory.create() 创建的东西最后放在callAdapterFactories
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // GsonConverterFactory.create() 创建的东西最后添加在converterFactories
      List<Converter.Factory> converterFactories =
          new ArrayList<>(1 + this.converterFactories.size());

     converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }

到这里我们知道Retrofit 创建的一些核心属性,callFactory, baseUrl 不必说 主要是converterFactoriescallAdapterFactoriescallbackExecutor 这三个参数。

我们先复习一下动态代理。

public interface IVehical {
    void run();
}

public class Car implements IVehical{

    @Override
    public void run() {
        System.out.println("Car run ...");
    }
}
@Test
public void testProxy(){
    IVehical iVehical = new Car();
    IVehical vehicalProxy = (IVehical) Proxy.newProxyInstance(iVehical.getClass().getClassLoader(), new Class[]{IVehical.class}, new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String name = method.getName();
            System.out.println("method name "+name);
            Object invoke = method.invoke(iVehical, args);
            return invoke;
        }
    });
    vehicalProxy.run();
}

最后我们打印结果是

I/System.out: method name run
Car run …
iVehical com.haocang.commonui.Car@78e78e6
vehicalProxy com.haocang.commonui.Car@78e78e6

根据我们打印结果我们可以发现 IVehical vehicalProxy 这实例最后执行了IVehical iVehical实例的run方法。 可以理解为Proxy.newProxyInstance 创建的对象其实就是IVehical iVehical 。事实也正的是如此,两者的地址是指向的同一个地址。

动态代理 需要三个参数classLoader 、接口类集合(传入的接口最终会被实现)、InvocationHandler回调,然后会返回一个接口的实例对象,当这个实例对象在调用接口定义的方法的时,会执行InvocationHandler回调的invoke方法,并且把调用的方法信息传给invoke作为参数。

接下来分析 retrofit.create方法,他的返回值是GitHubService service 实例

  public <T> T create(final Class<T> service) {
  	//验证service是一个接口,并且接口不能继承其他的接口
    Utils.validateServiceInterface(service);
	// validateEagerly 如果设置这个,会对GitHubService 里面编写的方法的合法性进行验证,通常为false
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //注释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 {
            // 如果method 不是listRepos 而是 Object里面的方法,比如 toString
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            // 如果是一个接口的实现的方法 如GitHubService里面已经实现的方法。
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            // 注释2 核心
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            // 注释3 核心
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            // 注释 4 核心
            return serviceMethod.adapt(okHttpCall);
          }
        });
  }

从动态代理的讲解,我们可以得出Proxy.newProxyInstance 会创建一个GitHubService的实例,当这个实例调用它的方法的时,InvocationHandlerinvoke就会被调用。
所以我们在执行Call<List<Repo>> repos = service.listRepos("octocat"); 执行的时候,invokeMethod method指的是listRepos, Object[] args 就是"octocat" 。接下来我们看invoke 方法的实现,首先他会判断GitHubService的实例 调用的是不是Object的方法,比如toString 。接下来判断platform.isDefaultMethod(method) 是否是已经实现的方法。 接下来就是通过invoke methd 参数得到一个ServiceMethod实例。

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() 我们传入了Retrofit实例和method。

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 方法的注解 @GET("users/{user}/repos")
      this.methodAnnotations = method.getAnnotations();
      // 获取方法的参数类型 String user
      this.parameterTypes = method.getGenericParameterTypes();
      // 获取方法的每个参数上的注解 @Path("user")
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

ServiceMethod.Builder 主要获取关于method一些信息,注解、 参数类型、 参数的注解。接下来看build方法

    public ServiceMethod build() {
    	// 根据method的返回类型 决定用什么转换器,比如 默认的Call 或者 RxJava2CallAdapter的Flowable
      callAdapter = createCallAdapter();
      //  以RxJava2CallAdapter为例获取到responseType
      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?");
      }
      // 通过 method 身上的信息 和 responseType 最终获取Response的Converter
      responseConverter = createResponseConverter();
		// 解析method身上的注解信息,比如是GET请求还是POST请求
      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).");
      }
		// 获取到method身上的参数信息,最后封装到ParameterHandler身上
      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) {} //抛异常

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      if (relativeUrl == null && !gotUrl) {}//抛异常
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {}//抛异常
      if (isFormEncoded && !gotField) {}//抛异常
      if (isMultipart && !gotPart) {}//抛异常

      return new ServiceMethod<>(this);
    }

这方法可以理解成解析method的信息,因为我们在method中注解了很多信息,如 请求方式、请求url、请求参数。最后封装到ServiceMethod里面。
接下来是 new OkHttpCall<>(serviceMethod, args) 这是Retrofit封装的一个Call对象,最终会创建成OkHttp的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;
  }

  okhttp3.Call toCall(@Nullable 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 callFactory.newCall(requestBuilder.build());
  }

从这里我们可以看到把我们传的argsparameterHandlers 一起,最后被封装到OKHttprequestBuilder身上最后被callFactory.newCall调用了转换成了RealCall.newRealCall

综上我们我们可以理解成把注解上的信息以及我们传递的参数,封装到一个okhttp的request上,最后newCall。其实就是在构建一个 okhttp请求。

接下来注释 3 serviceMethod.adapt(okHttpCall) 这个方法其实就是执行 方法。 执行我们调用的service.listRepos("octocat"); 从前一步我们封装了一个RealCall 对象,然后传递给serviceMethod.adapt() 这个是不是就是 在执行呢?

 okhttpcall.enqueue(new Callback() {})
 okhttpcall.execute()

接下来验证我们的猜想。

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

这里的callAdapter是一个接口,如果我们写的是 Rxjava的返回形式, Flowable<List<CommOrgEntity>> getOrganizations(); 那么他就是一个 RxJava2CallAdapter 。 如果我们是普通的 Call<List<Repo>> listRepos(@Path("user") String user) 就是一个ExecutorCallAdapter。我们直接看 RxJava2CallAdapter的实现。

  @Override public Object adapt(Call<R> call) {
  	//根据是同步还是异步 不同的 Observable
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);
	// 如果isResult 和 isBody 都不是并且isFlowable isSingle isMaybe isCompletable都是false
    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);
    }
	//如果是 Flowable 
    if (isFlowable) {
      return observable.toFlowable(BackpressureStrategy.LATEST);
    }
    if (isSingle) {
      return observable.singleOrError();
    }
    if (isMaybe) {
      return observable.singleElement();
    }
    if (isCompletable) {
      return observable.ignoreElements();
    }
    return observable;
  }

如果isResultisBody 都不是并且isFlowable isSingle isMaybe isCompletable都是false 那么他就是一个CallEnqueueObservable 对象。

  CallEnqueueObservable(Call<T> originalCall) {
    this.originalCall = originalCall;
  }

  @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
    // Since Call is a one-shot type, clone it for each new observer.
    Call<T> call = originalCall.clone();
    CallCallback<T> callback = new CallCallback<>(call, observer);
    observer.onSubscribe(callback);
    //核心方法
    call.enqueue(callback);
  }

补一下Rxjava的知识详细见 Rxjava的调用逻辑以及线程切换原理 一个Rxjava 的链条其实是层层嵌套,从数据源位置会调用subscribeActual产生数据,然后把传递给下一个Observer
我们可以看到最后他执行了call.enqueue(callback) 这也验证了上面我们的猜想。

总结 retrofit 的核心就只有一个方法 create,在这个方法里面启用了动态代理 创建了Service接口实例,当我们调用方法时,动态代理的InvocationHandlerinvoke方法被执行,并且把我们调用方法信息和参数信息传递给invoke 方法用methodargs 接受,通过method我们创建出 ServiceMethod对象,这个对象身上封装了注解信息,然后把这个对象传递给OkHttpCall 对象,他会得到ServiceMethodargs 生成 OkHttp 的RequestRealCall 实例。 最后根据我们的CallAdapter不同的实现,执行call.enqueue(callback)

发布了59 篇原创文章 · 获赞 16 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dingshuhong_/article/details/104697626