转载

Retrofit源码解析

retrofit是一种类型安全的HTTP客户端。所谓的类型安全,就是说在运行时不会报类型错误,它会在编译期检查。 要分析它的源码当然是从使用开始说起。在之前的例子中通过Retrofit.create()方法来生成网络请求对象,利用这个对象进行相关的同步或者异步请求。所以从这里开始。

public <T> T create(final Class<T> service) {
    //验证是否为接口而且是不继承其他接口的接口
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }

    //核心就是动态代理,就是创建一个对象,它会代理service(接口)中的每个方法,
    //然后把接口中的每个方法通过serviceMethod.callAdapter.adapt(okHttpCall);代替返回相应的结果
    //参数一:类加载器,参数二:动态代理代理的是哪些类,参数三
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
            new InvocationHandler() {
                //Anddroid的还是Java8、Java7等
                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.
                    //如果是Object类自有的方法就直接执行
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    //如果是平台中自有的方法也直接执行
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    ServiceMethod serviceMethod = loadServiceMethod(method);
                    //call就做了两件事
                    //一:生成一个真正的OKHTTP的call并且加入请求队列
                    //二:对返回结果利用之前定义的converter转换后返回给callback
                    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    //之所以会用adapter的adapt方法主要是为了线程切换(rxjava的转换),这里是把结果切回主线程
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

复制代码

先关方法的含义已经写到注释里了,因为上面这些核心的就是动态代理,它会代理service中的每个方法,既然是代理接口类的每个方法,那么首先是找到方法 loadServiceMethod(method);

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;
}
复制代码

从上面可以看出无非就是之前加载过的话就从缓存中取,没加载过的话就的重新构建并且加入到缓存中。找到方法之后则很自然的要执行这个方法,那就得是OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);通过这步把要执行的方法及参数保存到了OKHTTP的call中,当执行enqueque的时候则真正的用得到的方法和参数请求网络。 在基本使用中,构造完网络请求对象之后,就用这个对象进行实际的网络请求,比如异步的enquue。

@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) {
        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)
        throws IOException {
      Response<T> response;
      try {
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        callFailure(e);
        return;
      }
      callSuccess(response);
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    private void callFailure(Throwable e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    private void callSuccess(Response<T> response) {
      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}
复制代码

上面代码中最重要的则是 createRawCall() ,也就是创建OKHTTP的call,然后利用这个call调用OKHTTP的enqueque来进行真正的网络请求,同时将返回值返回到callback中。 到这里已经可以拿到网络通信结果了当然是通过 parseResponse(rawResponse) 转换的最终结果,而这个转换则是通过初始化时 addConverterFactory 添加的转换器,为什么不直接返回这个okHttpCall而是还要进行下一步 return serviceMethod.callAdapter.adapt(okHttpCall); 那就得看一下OKHTTP的enqueque做了什么

@Override public void enqueue(Callback responseCallback) {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

复制代码

OKHTTP的实现类中的enqueue调用了 client.dispatcher().enqueue(),继续看这个enqueque

synchronized void enqueue(AsyncCall call) {
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    runningAsyncCalls.add(call);
    executorService().execute(call);
  } else {
    readyAsyncCalls.add(call);
  }
}
复制代码

从这个理可以看出来如果当前发送请求的数量大于 maxRequests (当前源码数量为64),加入队列待执行,如果没到则执行,而执行的代码可以清楚的看到使用executorService().execute(call)。说明在后台线程池中进行的请求和返回。那么到这里就大致的可以推断出return adatp的作用了,那就是 线程切换 。 直接跟进去发现adapt方法是在接口类中,那么我们直接找它的实现类看看,一共有两个即 ExecutorCallAdapterFactoryDefaultCallAdapterFactory ,然后再看这两个类在那儿用的,发现是在下面这个方法中调用的

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor != null) {
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
  return DefaultCallAdapterFactory.INSTANCE;
}
复制代码

而这个方法有又是retrofit的build()方法中,也就是刚才说的初始化话过程中已经做了

public Retrofit build() {
    if (baseUrl == null) {
      throw new IllegalStateException("Base URL required.");
    }

    okhttp3.Call.Factory callFactory = this.callFactory;
    if (callFactory == null) {
      callFactory = new OkHttpClient();
    }

    Executor callbackExecutor = this.callbackExecutor;
    if (callbackExecutor == null) {
      callbackExecutor = platform.defaultCallbackExecutor();
    }

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

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

    return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
        callbackExecutor, validateEagerly);
  }
}
复制代码

而在这个方法中我们看到需要向方法中传一个callbackExecutor,而这个executor从字面看就是与平台相关的,那么Android平台的是什么样子呢

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);
    }
  }
}
复制代码

从handler.post我们一下子就豁然开朗了。 大框架已经已经说完了,那么那些注解什么时候用的呢,那就得从构造方法和参数入手了,仔细看一下

ServiceMethod.Builder<>(this, method).build();
public ServiceMethod build() {
  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);
}
复制代码

从上面的源码可以看出首先创建了最后一步需要的callAdapter,然后创建ResponseConverter,也就是通常的将结果转化为Gson等的转换器。然后解析方法注解parseMethodAnnotation(annotation);、解析参数注解parseParameter(p, parameterType, parameterAnnotations)。最后生成的请求和返回所需要的全部参数如下

ServiceMethod(Builder<R, T> builder) {
  this.callFactory = builder.retrofit.callFactory();
  this.callAdapter = builder.callAdapter;
  this.baseUrl = builder.retrofit.baseUrl();
  this.responseConverter = builder.responseConverter;
  this.httpMethod = builder.httpMethod;
  this.relativeUrl = builder.relativeUrl;
  this.headers = builder.headers;
  this.contentType = builder.contentType;
  this.hasBody = builder.hasBody;
  this.isFormEncoded = builder.isFormEncoded;
  this.isMultipart = builder.isMultipart;
  this.parameterHandlers = builder.parameterHandlers;
}
复制代码
原文  https://juejin.im/post/5d0df7846fb9a07ea803d3a1
正文到此结束
Loading...