文章目录

  • 一.参考博客
  • 二.Retrofit的介绍
  • 三.什么是动态代理
  • 四. Retrofit.Create()方法
  • 五. ServiceMethod
  • 六. 初看HttpServiceMethod
  • 七. OkHttpCall
  • 八. 响应结果是如何解析的
    • 8.1 Converter 与 GsonConverterFactory
    • 8.2 我们添加的ConverterFactory是怎么被调用到的
    • 8.3 总结
  • 九. 请求注解参数是如何解析的
  • 十. Call是如何转换的
    • 10.1 CallAdapter
    • 10.2 我们添加的CallAdapterFactory是怎么被调用的
  • 11. Retrofit & Android
  • 十二 . 再看ServiceMethod
  • 十三 . 回过头来看Retrofit实例的创建
  • 十四 . 总结

一.参考博客

三方库源码学习-1 :OkHttp
一定能看懂的 Retrofit 最详细的源码解析!
三方库源码笔记(7)-Retrofit 源码详解
又看一遍Retrofit源码,这次写了篇笔记

二.Retrofit的介绍

官方介绍: A type-safe HTTP client for Android and Java. 这说明 Retrofit 的内部实现并不需要依赖于 Android 平台,而是可以用于任意的 Java 客户端,Retrofit 只是对 Android 平台进行了特殊实现而已。

使用:
可以参考官网:Retrofit
看我之前的博客:Andrioid网络请求—— Retrofit的简单使用

这里给出一个小例子:
版本基于2.9.0


```java
public interface GitHubService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);
}
public class RetrofitRequest {Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).build();GitHubService service = retrofit.create(GitHubService.class);Call<List<Repo>> repos = service.listRepos("octocat");
}

三.什么是动态代理

在介绍Retrofit之前,先插播一下动态代理

动态 指的是在运行期,而 代理 指的是实现了接口的类,实现了接口的方法,称之为代理。有时候,对于某个既定的interface,我们不希望直接声明并使用其实现类,而是希望实现类可以动态生成,此时就可以通过 Proxy.newProxyInstance 来实现目的。

看一个简单的代理模式的例子。

interface FaceDemo {fun run(user : String)
}
fun main(args: Array<String>) {val request = Proxy.newProxyInstance(FaceDemo::class.java.classLoader,arrayOf<Class<*>>(FaceDemo::class.java),object : InvocationHandler{override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {return println("method = ${method?.name} args : ${args?.get(0)} ")}})  as FaceDemoprintln(request.javaClass)//调用方法request.run("liHua")
}

运行结果:

可以看到:

  • InvocationHandler.invoke() 方法拦截了我们调用的接口中的方法。
  • 在运行时这个类是一个 $Proxy0 的类。

实际上通过代理模式,我们定义的接口会动态的创建出实现类也就是 $Proxy0 类,它大概长下面这个样子。

class $Proxy0 extends Proxy implements FaceDemo {protected $Proxy0(InvocationHandler h) {super(h);}private static Method m3;static {m3 = Class.forName("FaceDemo").getMethod("FaceDemo", new Class[] {Class.forName("java.lang.String"),});}@Overridepublic void run(String user) {/* h就是我们自己创建的InvocationHandler,所以最终就回调到它里面的invoke方法内执行*/super.h.invoke(this, m3, new Object[]{user});}
}

四. Retrofit.Create()方法

从 create() 方法往下深入。


```java
public <T> T create(final Class<T> service) {validateServiceInterface(service);  // 1return (T)     //2Proxy.newProxyInstance(service.getClassLoader(),new Class<?>[] {service},new InvocationHandler() {@Overridepublic @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {......return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args): loadServiceMethod(method).invoke(args);}});}

注释1:这个是用来验证我们定义的GitHubService是一个接口,且不是泛型接口,并且会判断是否进行提前验证,提前验证可以更好的把错误暴漏在编译器,但是比较耗时,可能造成卡顿。

注解2:这里其实就是用了动态代理来处理的。借助动态代理拿到接口的实现类,当调用接口的方法时,会回调到它里面的 invoke() 方法。并在 invoke() 方法中拿到声明listRepos() 时标注的各个配置项。

这个方法的关键代码就是loadServiceMethod(method).invoke(args) 。主要逻辑就是把method对象转换为ServiceMethod对象,并做缓存。在下次使用相同的请求方法时,直接从缓存池中取ServiceMethod对象,优化了性能。

//1
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();ServiceMethod<?> loadServiceMethod(Method method) {ServiceMethod<?> result = serviceMethodCache.get(method);//2if (result != null) return result;synchronized (serviceMethodCache) {result = serviceMethodCache.get(method);if (result == null) {//3result = ServiceMethod.parseAnnotations(this, method);//4serviceMethodCache.put(method, result);}}return result;}

注解1:创建一个Map集合,把ServiceMethod对象缓存起来,因为同一个请求方法可能会被调用多次,缓存提升性能。

注解2:如果该方法已经被缓存过了,直接用原来缓存的ServiceMethod

注解3:将每个代表接口方法的 method 对象转换为 ServiceMethod 对象,该对象中就包含了接口方法的具体信息。

注解4:把拿到的ServiceMethod对象缓存进集合中。

五. ServiceMethod

刚才的loadServiceMethod(method) 方法返回的就是一个ServiceMethod。它是一个抽象类,主要的逻辑如下:

  1. 拿到 RequestFactory对象,这个是用来解析注解的。后面再讲。
  2. 通过HttpServiceMethod.parseAnnotations 来获取ServiceMethod的实现类。

这里运用了工厂模式,由于最终的网络请求方法可能是多种多样的,既可以通过线程池来执行,又可以通过Kotlin协程来执行。使用工厂模式就可以把这种差异隐藏在不同的ServiceMethod实现类里。而外部都是通过parseAnnotations来获取实现类。

abstract class ServiceMethod<T> {static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//1 这里拿到了requestFactory对象,它是用来解析注解的RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);Type returnType = method.getGenericReturnType();.......//2  使用工厂模式拿到ServiceMethod实现类return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}abstract @Nullable T invoke(Object[] args);
}

注意这里还有一个抽象方法 invoke ,而在刚才动态代理的invoke方法中,最终调用的就是一个invoke方法,所以这个方法的实现很关键。

六. 初看HttpServiceMethod

HttpServiceMethod 是 ServiceMethod的唯一直接子类。而它本身也是一个抽象类。我们先顺着刚才的思路往下走,等会在来看这个类。

现在主要看一下 invoke 方法。主要的逻辑是:

  1. 创建OkHttpCall对象。这是实际进行网络请求的类。
  2. 把刚才拿到的 Call < ResponseT > 对象通过adapt进行适配为我们需要的Call并返回。

```javafinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}

我们先看OkHttpCall这个类。

七. OkHttpCall

这个类是 retrofit2.Call 的实现类,是真正发起OkHttp请求的地方。当我们调用 call.enqueue(Callback) 方法时,最终就会调用到这里的OkHttpCall.enque方法。

  • OkHttpCall.enqueue
@Overridepublic void enqueue(final Callback<T> callback) {okhttp3.Call call;call = rawCall;failure = creationFailure;if (call == null && failure == null) {//1:创建了okhttp3.Call callcall = rawCall = createRawCall();}//调用的是okHttp3.call.enqueue,所以这里的代码是发生在OkHttp中的call.enqueue(new okhttp3.Callback() {@Overridepublic void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {Response<T> response;//2 :对拿到的结果进行解析response = parseResponse(rawResponse);//成功之后的回调callback.onResponse(OkHttpCall.this, response);}//失败的回调@Overridepublic void onFailure(okhttp3.Call call, IOException e) {callFailure(e);}private void callFailure(Throwable e) {callback.onFailure(OkHttpCall.this, e);}});}

这个方法的主要逻辑就是创建出OkHttp的Call,并调用它的enqueue方法发起请求。最后对响应结果进行处理。并调用回调接口把结果返回。

  • OkHttpCall.execute
public Response<T> execute() throws IOException {okhttp3.Call call;synchronized (this) {//拿到OkHttp的call对象call = getRawCall();}//这里调用了call.execute(),实际的网络请求已经发生了,并把响应结果//传到 parseResponse中进行解析return parseResponse(call.execute());}

八. 响应结果是如何解析的

顺着刚才的代码往下走:

//OkHttpCall.parseResponse
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();// Remove the body's source (the only stateful object) so we can pass the response along.rawResponse =rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();//拿到返回码int code = rawResponse.code();//如果状态码不是2XX,说明请求有问题,比如3XX需要重定向,4XX服务端无法处理请求//5XX服务端处理请求出错if (code < 200 || code >= 300) {return Response.error(bufferedBody, rawResponse);}//204是成功的状态码,但是响应头没有body数据,所以直接返回null,if (code == 204 || code == 205) {rawBody.close();return Response.success(null, rawResponse);}//如果走到这,说明一切正常了,需要我们解析返回的结果,拿到我们需要的结果类型ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);//1 通过 responseConverter 转换 ResponseBodyT body = responseConverter.convert(catchingBody);return Response.success(body, rawResponse);}

注释 1:通过 responseConverter 调用 invoke 方法,来进行结果的处理。

8.1 Converter 与 GsonConverterFactory

这个 responseConverter的实现是在HttpServiceMethod的parseAnnotations中。

我们在继续跟代码之前先看看这个东西是什么:

Converter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType);

可以看到它是一个 Converter 对象。Converter是一个接口,里面通过有一个 converter 方法,和一个抽象类 Factory ,它是用来创建Converter的实现类的。

我们需要的解析结果可能是多种多样的,Retrofit事先并不知道,所以提供了这样一个接口。我们需要解析何种响应就创建对应的Converter实现类。Retrofit会把ResponseBody传进这个实现类,并通过调用它的 converter() 方法拿到对应的解析结果。

public interface Converter<F, T> {@NullableT convert(F value) throws IOException;abstract class Factory {public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {return null;}    }
}

我们通过gson解析对应的转换器来验证一下:

public final class GsonConverterFactory extends Converter.Factory {@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,Retrofit retrofit) {TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));return new GsonResponseBodyConverter<>(gson, adapter);}
}
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {......@Override public RequestBody convert(T value) throws IOException {Buffer buffer = new Buffer();Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);JsonWriter jsonWriter = gson.newJsonWriter(writer);adapter.write(jsonWriter, value);jsonWriter.close();return RequestBody.create(MEDIA_TYPE, buffer.readByteString());}
}

可以看到我们平时使用的GsonConverterFactory继承自Converter.Factory,并且通过实现responseBodyConverter方法拿到了Converter实现类,里面的 converter() 方法就是Gson对应的解析方法。

8.2 我们添加的ConverterFactory是怎么被调用到的

继续跟之前的代码。
这个 responseConverter 经过层层调用最终的源头在 Retrofit.nextResponseBodyConverter

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {int start = converterFactories.indexOf(skipPast) + 1;for (int i = start, count = converterFactories.size(); i < count; i++) {Converter<ResponseBody, ?> converter =converterFactories.get(i).responseBodyConverter(type, annotations, this);if (converter != null) {return (Converter<ResponseBody, T>) converter;}}
}

上面的代码可以看到是通过遍历converterFactories集合拿到每一个Converter对象,如果不是null的话,就会选择到对应的解析处理器,完成数据解析。如果最终没有找到一个合适的处理器的话,就会抛出 IllegalArgumentException。

converterFactories又会添加那些解析处理器呢?

这个添加的过程是在 Retrofit.build 方法中完成的。

 public Retrofit build() {//创建出converterFactories集合List<Converter.Factory> converterFactories =new ArrayList<>(1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());//1        converterFactories.add(new BuiltInConverters());//2converterFactories.addAll(this.converterFactories);//3converterFactories.addAll(platform.defaultConverterFactories());

注解1:在converterFactories中添加默认构建的转换器,BuiltInConverters这个是最先被添加的,所以不应该返回是拿到这个转换器吗?

public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {if (type == ResponseBody.class) {return }if (type == Void.class) {return }if (checkForKotlinUnit) {if (type == Unit.class) {return }return null;}

可以看到BuiltInConverters转换器只有在目标类型为 ResponseBody、Void、Unit三种类型的情况下不会返回null,其他情况都返回null。所以当我们需要的类型不是上诉三种情况就会继续遍历转换器集合。
注解2: 这里是把我们addConverterFactory中添加的转换器全部添加进转换器集合。所以如果我们添加的gson转换器会在这里被添加。也可以看到如果我们添加多个转化器的话,一般情况只有第一个是正常工作的。
注解3:如果是 Java8 就是一个OptionalConverterFactory 的转换器,否则就是一个空的。

8.3 总结

  • Retrofit 创建了 Converter 用来对响应结果进行转换,用户可以添加转换器来转换响应结果为我们需要的类型。最典型的GsonConverterFactory。
  • Retrofit会默认为我们添加BuiltInConverters转换器,如果我们需要的数据类型不是ResponseBody,Void,Unit 。这个转换器将不起作用。
  • 如果没有找到合适的处理器的话会抛出异常。
  • 如果添加多个处理器,最早被添加的会被最先匹配使用。比如添加了两个GsonConverterFactory,第二个是不会工作的。

九. 请求注解参数是如何解析的

在OkHttpCall里面有个createRawCall()方法是用来获取OkHttp3.Call的。它里面完成了OkHttp的拼装。

private okhttp3.Call createRawCall() throws IOException {okhttp3.Call call = callFactory.newCall(requestFactory.create(args));return call;}

可以看到通过调用 requestFactory.create(args) 这个方法获得了Request实例。 通过这个方法的调用,最终把 interface 的注解和各个参数, baseUri等拼成了OkHttp请求要用到的Request。

requestFactory实例的获取是在ServiceMethod中。

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {//获取requestFactory并将他向下传递给HttpServiceMethodRequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);}

RequestFactory.java

final class RequestFactory {static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {return new Builder(retrofit, method).build();}//build()方法RequestFactory build() {// 1,转换方法注解for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}   ...// 2,对方法的每个参数生成一个ParameterHandler,存在数组中int parameterCount = parameterAnnotationsArray.length;parameterHandlers = new ParameterHandler<?>[parameterCount];for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {parameterHandlers[p] =parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);}...return new RequestFactory(this);}

在上面的代码中,build方法中主要做了两件事,一是解析方法上的注解,另一件事是解析方法参数上的注解,然后每个参数生成一个ParameterHandler存放在数组上。而省略的那些代码是一些检验信息,比如没有body的一些请求方式不能含有Body,FormUrlEncoded必须有Field注解等。

总结:RequestFactory 采用了 Builder 模式,包含了对接口方法的各项处理结果. 并最终拼装为一个Request对象返回。

十. Call是如何转换的

在刚才分析HttpServiceMethod.invoke 方法时说过它主要有两个逻辑:

@Overridefinal @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);}
  1. 创建OkHttpCall对象。这是实际进行网络请求的类。
  2. 把刚才拿到的 Call < ResponseT > 对象通过adapt进行适配为我们需要的Call并返回。

这第二步是如何完成的呢?

10.1 CallAdapter

在继续跟进之前,解释一下CallAdapter

public interface CallAdapter<R, T> {//返回具体的内部类型,即 RepoType responseType();//用于将 Call 进行转化T adapt(Call<R> call);abstract class Factory {//用于提供将  CallAdapter 对象//如果此 CallAdapter 无法完成这种数据类型的转换,那么就返回 nullpublic abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);}}
}

CallAdapter是请求适配器,在Retrofit中,网络请求的实体就是OkHttpCall。而CallAdapter就是对它进行处理,将它变成更加方便我们使用的形式。并且如果是使用 RxJava 进行网络请求,我们还可以把它适配成 RxJava 对应的请求方式。这里使用了适配器模式

看一下 RxJava2CallAdapterFactory

public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {public static RxJava2CallAdapterFactory create() {return new RxJava2CallAdapterFactory(null, false);}@Override public @Nullable CallAdapter<?, ?> get(return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,isSingle, isMaybe, false);}
}
@Override public Object adapt(Call<R> call) {Observable<Response<R>> responseObservable = isAsync? new CallEnqueueObservable<>(call): new CallExecuteObservable<>(call);return RxJavaPlugins.onAssembly(observable);}

可以看到 RxJava2CallAdapterFactory继承自CallAdapter.Factory,并调用get 方法拿到了CallAdapter实例。并最终在它的adapt方法里完成类型转换。

10.2 我们添加的CallAdapterFactory是怎么被调用的

刚才的adapt是HttpServiceMethod的一个抽象方法,最终调用的是callAdapter.adapt(call)
而这个callAdapter是在HttpServiceMethod.parseAnnotations中被创建的。

CallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);

继续往下跟进,最终在Retrofiot.nextCallAdapter中拿到了callAdapter对象。

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {int start = callAdapterFactories.indexOf(skipPast) + 1;for (int i = start, count = callAdapterFactories.size(); i < count; i++) {CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);if (adapter != null) {return adapter;}}}

上面的代码可以看到是通过遍历callAdapterFactories集合拿到每一个Converter对象,如果不是null的话,就会选择到对应的请求适配器,完成适配工作。如果最终没有找到一个合适的适配器的话,就会抛出 IllegalArgumentException。

callAdapterFactories又会添加那些请求适配器呢?

在Retrofit.build() 方法中:

//首先用用户添加的callAdapterFactory构建callAdapterFactories
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//在最后添加一个默认的适配器
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

这个集合会先把用户设置的callAdapterFactory添加进集合中,然后再最后添加一个默认的适配器。

11. Retrofit & Android

Retrofit 的内部实现并不需要依赖于 Android 平台,而是可以用于任意的 Java 客户端,Retrofit 只是对 Android 平台进行了特殊实现而已。那么,Retrofit 具体是对 Android 平台做了什么特殊支持呢?

在构建 Retrofit 对象的时候,我们可以选择传递一个 Platform 对象用于标记调用方所处的平台

public static final class Builder {private final Platform platform;private @Nullable okhttp3.Call.Factory callFactory;private @Nullable HttpUrl baseUrl;private final List<Converter.Factory> converterFactories = new ArrayList<>();private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();private @Nullable Executor callbackExecutor;private boolean validateEagerly;Builder(Platform platform) {this.platform = platform;}//如果不设置,会自动设置一个Platformpublic Builder() {this(Platform.get());}

Platform 类有两个作用:

  1. 判断是否支持 Java 8。
  2. 实现 main 线程回调的 Executor。
class Platform {private static final Platform PLATFORM = findPlatform();static Platform get() {return PLATFORM;}//根据 JVM 名字来判断使用方是否是 Android 平台private static Platform findPlatform() {return "Dalvik".equals(System.getProperty("java.vm.name"))? new Android() //: new Platform(true);}//是否支持 Java 8private final boolean hasJava8Types;private final @Nullable Constructor<Lookup> lookupConstructor;Platform(boolean hasJava8Types) {......}//获取默认的 Executor 实现,用于 Android 平台@NullableExecutor defaultCallbackExecutor() {return null;}List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);return hasJava8Types? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory): singletonList(executorFactory);}}

Platform 类只具有一个唯一子类,即 Android 类。其主要逻辑就是重写了父类的 defaultCallbackExecutor()方法,通过 Handler 来实现在 main 线程执行特定的 Runnable,以此来实现网络请求结果都在 main 线程进行回调。

 static final class Android extends Platform {Android() {super(Build.VERSION.SDK_INT >= 24);}@Overridepublic Executor defaultCallbackExecutor() {return new MainThreadExecutor();}static final class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());@Overridepublic void execute(Runnable r) {handler.post(r);}}}

刚才说过callAdapterFactories会在最后添加默认的请求适配器,这个请求适配器就来自于Platform.defaultCallAdapterFactories。看一下这个默认的请求适配器。

DefaultCallAdapterFactory 会拿到 Platform 返回的 Executor 对象,如果 Executor 对象不为 null 且接口方法没有标注 SkipCallbackExecutor 注解的话,就使用该 Executor 对象作为一个代理来中转所有的回调操作,以此实现线程切换。这里使用到了装饰器模式

final class DefaultCallAdapterFactory extends CallAdapter.Factory {private final @Nullable Executor callbackExecutor;//构造器,如果是Android平台,就会在这里拿到对应的可以回调到主线程的线程池DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {this.callbackExecutor = callbackExecutor;}@Overridepublic @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {return new CallAdapter<Object, Call<?>>() {@Overridepublic Type responseType() {return responseType;}@Overridepublic Call<Object> adapt(Call<Object> call) {return executor == null ? call : new ExecutorCallbackCall<>(executor, call);}};}

ExecutorCallbackCall

stati/c final class ExecutorCallbackCall<T> implements Call<T> {//拿到对应的线程池final Executor callbackExecutor;//这个就是通过OKHttpCall拿到的那个call<Response>对象final Call<T> delegate;//调用enqueue方法@Overridepublic void enqueue(final Callback<T> callback) {Objects.requireNonNull(callback, "callback == null");//    内部去调用OKHttpCall.enqueuedelegate.enqueue(new Callback<T>() {@Overridepublic void onResponse(Call<T> call, final Response<T> response) {//拿到响应结果后切换线程,通过callback将结果传出callbackExecutor.execute(() -> {if (delegate.isCanceled()) {callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}});}@Overridepublic void onFailure(Call<T> call, final Throwable t) {callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));}});}@Overridepublic Response<T> execute() throws IOException {return delegate.execute();}}
}

其实这个才是一切的起点,当外部调用enqueue或者execute发起请求时,最先是传递到这儿,然后再一层一层传递到OkHttpCall,把请求交给OkHttp处理。

十二 . 再看ServiceMethod

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {//判断是否是使用Kotlin的方法来实现的。boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;//拿到请求适配器CallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);//拿到数据转换器Converter<ResponseBody, ResponseT> responseConverter =createResponseConverter(retrofit, method, responseType); //拿到OkHttpClientokhttp3.Call.Factory callFactory = retrofit.callFactory;//获取HttpServiceMethod对象实例   if (!isKotlinSuspendFunction) {//如果不是使用Kotlin的方法来请求的,调用的是CallAdapted,主要就是实现了HttpserviceMethod的adapt方法return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);} //如果是,就 调用 Kotlin的方法来获取HttpserviceMethod的adapt实例。else if (continuationWantsResponse) {return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForResponse<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);} else {return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForBody<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,continuationBodyNullable);}

下面就是通过Kotlin的方法来发起请求后的adapt实现

@Overrideprotected Object adapt(Call<ResponseT> call, Object[] args) {call = callAdapter.adapt(call);Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];try {return isNullable? KotlinExtensions.awaitNullable(call, continuation): KotlinExtensions.await(call, continuation);} catch (Exception e) {return KotlinExtensions.suspendAndThrow(e, continuation);}}

ServiceMethod 几乎 包含了一个网络请求所需要的所有数据。

总结一下这个类的行为:

  • 获取注解处理器(RequestFactory),和方法参数args 一块向下传递给OkHttpCall用于解析注解,构建Request实例。
  • 获取数据转换器(responseConverter),向下传递给OkHttpCall用于将网络请求的结果进行解析。比如Gson解析。
  • 获取OkHttpClient的实例 callFactory,向下传递给OkHttpCall用于构建OkHttp请求
  • 获取请求适配器(CallAdapter),用于将网络请求的Call实体,包装为更方便我们使用的形式。比如适配RXjava,Android平台自动将回调结果切换到主线程等。
  • 支持Kotlin协程

十三 . 回过头来看Retrofit实例的创建

Retrofit 的创建使用了Builder模式 , 主要的配置如下:

  • Platform(平台类型)
    我们可以自定义平台类型,如果没有设置,Retrofit会为我们自动创建。Android平台的默认类型为Android。主要的作用是:判断是否支持 Java 8,实现main线程回调的线程池。并且创建了默认的请求适配器DefaultCallAdapterFactory。

  • callFactory(网络请求工厂)

public Builder client(OkHttpClient client) {return callFactory(Objects.requireNonNull(client, "client == null"));}public Builder callFactory(okhttp3.Call.Factory factory) {this.callFactory = Objects.requireNonNull(factory, "factory == null");return this;}

Retrofit中网络请求工厂的默认实现是OkHttpClient,它是默认通过OkHttp发起网络请求的,此外,我们还可以自己设置OkHttpClient对象,可以加上自定义拦截器,设置超时时间等等。再者,如果不想用OkHttp,我们还可以设置自己的Factory类来使用。

  • baseUrl
  public Builder baseUrl(URL baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");return baseUrl(HttpUrl.get(baseUrl.toString()));}public Builder baseUrl(String baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");return baseUrl(HttpUrl.get(baseUrl));}public Builder baseUrl(HttpUrl baseUrl) {Objects.requireNonNull(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;}

可以通过URL,String,HttpUrl三种方式来设置baseUrl。实际上他们最终都被设置为HttpUrl。注意它设置的三点要求:

  • baseUrl不为空

  • 若是带有路径的话,则必须以 / 结尾

    错误:https://www.wanandroid.com/user

    正确:https://www.wanandroid.com/user/

  • 若是不带路径的话,则没有要求

  • callbackExecutor(回调线程池)

    设置回调的线程池,默认就是平台类型里面设置的默认线程池,Android平台就是切换到主线程的线程池。此外我们还可以自己定义回调的线程池,该线程池会被传到默认的请求适配器。

  • callAdapterFactories(请求适配器工厂集合)

    是一个List集合,其内部存放着多个CallAdapter.Factory的实例。用来生产CallAdapter的,而CallAdapter会把我们网络请求得到的Call进行适配,变为方便我们使用的Call。如果我们使用RXjava进行网络请求,就要设置RxJava2CallAdapterFactory。我们设置的CallAdapterFactory会被添加到这个集合中,并在集合的末尾添加默认的请求适配器 DefaultCallAdapterFactory。在获取CallAdapter实例时,会遍历这个集合,根据返回类型找到合适的CallAdapter。如果拿不到合适的,会出现异常。

  • converterFactories(数据转换器工厂集合)

    同样是一个List集合,其内部存放这多个Converter.Factory的实例。用来生产Converter的,而Converter会把我们进行网络请求获取的ResponseBody进行转换为我们需要的类型。比如把ResponseBody类型转换为实体的一个类,那么就可以添加GsonConverterFactory,使用Gson进行最后的数据转换。这个集合首先会添加一个BuiltInConverters(),这个转化器在目标类型不是ResponseBody、Void、Unit 这三种类型时会返回null。接着添加我们定义的转换器。最后添加一个默认的转换器。在获取Converter实例时,会遍历这个集合,根据返回类型找到合适的Converter。如果拿不到合适的,会出现异常。

  • validateEagerly(提前验证的开关)

    默认为false,如果设置为true,可以进行提前加载接口,可以更好的把错误暴露在编译器,但是比较耗时,可能造成卡顿。

十四 . 总结

Retrofit 的原理就是,拦截到方法、参数,再根据我们在方法上的注解,去拼接为一个正常的OkHttp 请求,然后执行。

首先在创建Retrofit时,会设置平台类型(Platform),Android平台就是对应的Android对象。请求的baseUrl网络请求工厂(OkHttpClient), 请求适配器工厂(RxJava2CallAdapterFactory),数据转换器工厂(GsonConverterFactory)等。并且设置的请求适配器工厂,数据转换器工厂还会被添加进各自的工厂集合。此外还有一些默认的适配器,转换器也会被添加进去。

然后它会根据定义的请求接口 获取一个接口实例,这里是通过动态代理来实现的。当用这个接口实例对象调用它里面的方法获取Call对象时,就会被这个动态代理对象(Proxy.newProxyInstance())拦截,然后调用自身(InvocationHandler)的 invoke()。它主要就是拦截功能。

在invoke()方法里,它首先会调用loadServiceMethod 方法,这个方法提供了一个缓存功能,当通过当前的method获取到对应的ServiceMethod对象后,它会对它进行缓存。如果下次使用相同的请求方法,就直接从缓存池中获取ServiceMethod对象。

当构建ServiceMethod对象时,首先它会根据请求方法(method)和 返回值类型拿到 数据转换器(responseConverter),请求适配器(CallAdapter),以及 注解处理器(requestFactory) 和网络请求工厂(callFactory)实例。来一起构建一个SerViceMethod。这个ServiceMethod对象几乎包含了要进行网络请求的所有数据。

当构建完SerViceMethod后,就会调用它的invoke() 方法。这个方法会创建一个okhttpCall,就是网络请求对象。在将其传入到SerViceMethod的adapt方法中。根据刚才获取到的请求适配器来确定返回的对象。如果是Retrofit默认的网络请求适配器,就返回一个Call对象,如果是Rxjava,就返回一个observable对象。

接下来就是发生请求的部分,以android平台返回的Call对象为例。它是对于Okhttp类的封装,所以也是两种请求方法,即同步和异步。

同步请求时,它会用 注解处理器(requestFactory)获取到Request实例,和刚才获取到的网络请求工厂(callFactory) 创建出Call实例,然后调用call的execute方法发送请求,最后调用ServiceMethod中的数据转化器对返回的数据进行解析。

异步请求时,它也是先创建一个Request对象,并进行网络请求,最后也是调用ServiceMethod中的数据转化器对返回的数据进行解析。不过和同步请求方法不同的在于,它其中牵扯到了线程切换。

请求完毕后会将回调方法交给回调执行器,它在里面获取了主线程的handler,通过这个handler切换到主线程。

三方库源码学习2-Retrofit相关推荐

  1. android 三方_面试官送你一份Android热门三方库源码面试宝典及学习笔记

    前言 众所周知,优秀源码的阅读与理解是最能提升自身功力的途径,如果想要成为一名优秀的Android工程师,那么Android中优秀三方库源码的分析和理解则是必备技能.就拿比较热门的图片加载框架Glid ...

  2. Android主流三方库源码分析(九、深入理解EventBus源码)

    一.EventBus使用流程概念 1.Android事件发布/订阅框架 2.事件传递既可用于Android四大组件间通信 3.EventBus的优点是代码简洁,使用简单,事件发布.订阅充分解耦 4.首 ...

  3. Python Sklearn库源码学习--kmeans

    前言: 分析体检数据希望不拘泥于Sklearn库中已有的聚类算法,想着改一下Kmeans算法.本着学习的目的,现在开始查看sklearn的源代码.希望能够写成一个通用的包. 有必要先交代一下我使用的p ...

  4. 陈硕Muduo库源码学习:EventLoop

    本人原本从事C++的学习的,现在进行即时通讯的网络开发学习,涉及到了muduo库顾muduo库进行深入学习,muduo库是给予reactor模型的并发处理的网络库,其广泛的利用了回调函数的特性. Ev ...

  5. Masonry 源码学习整理

    @(第三方库源码学习) [TOC] Masonry框架的类结构 学习一.Masonry采用了经典的组合设计模式(Composite Pattern). 1.定义 将对象组合成树状结构以表示" ...

  6. postgresql源码学习(57)—— pg中的四种动态库加载方法

    一. 基础知识 1. 什么是库 库其实就是一些通用代码,可以在程序中重复使用,比如一些数学函数,可以不需要自己编写,直接调用相关函数即可实现,避免重复造轮子. 在linux中,支持两种类型的库: 1. ...

  7. DotText源码学习——ASP.NET的工作机制

    --本文是<项目驱动学习--DotText源码学习>系列的第一篇文章,在这之后会持续发表相关的文章. 概论 在阅读DotText源码之前,让我们首先了解一下ASP.NET的工作机制,可以使 ...

  8. PostgreSQL源码学习(1)--PG13代码结构

    PostgreSQL源码学习(1)–PG13代码结构 PostgreSQL代码结构 Bootstrap:用于支持Bootstrap运行模式,该模式主要用来创建初始的模板数据库. Main:主程序模块, ...

  9. AFNetworking源码学习

    AFNetworking源码学习 简介 AFNetWorking是使用Objective-c开发iOS程序主流的网络请求开源库. AFNetworking组织结构 AFNetWorking主要分为5个 ...

最新文章

  1. 记一次订单号重复的事故,快看看你的 uuid 在并发下还正确吗?
  2. 没有 5G 版 iPhone 的苹果秋季发布会,发布了些什么?
  3. C# Revert 单词反转字符串!『测试通过』
  4. 算法----------同构字符串(Java版本)
  5. IOS中通知中心(NSNotificationCenter)的使用总结
  6. matlab 连通分支,(完整版)图的连通性判断matlab实验报告
  7. windows主机防护
  8. 深度学习 训练吃显卡_在深度学习中喂饱GPU
  9. ubuntu搜狗输入法突然无法使用(新解)
  10. 企业中常见的推荐系统架构(附交流视频和PPT下载链接)
  11. Linux中/etc/fstab /etc/mtab /proc/mounts这三个文件的分析与比较
  12. flash电脑安装包_Flash动画制作,Animate CC 2019下载安装
  13. sqlmap自动化注入工具使用浅析
  14. 【Dart语言第5篇】运算符
  15. Hack the box: Bastion
  16. 通过读取csv/xml数据并且结合使用allure展示测试报告,验证开发中的add()和reduct()操作(在@allure.story分别实现相加减)
  17. 如何继承字走三国武器
  18. 电大计算机基础期末考试题库,中央电大计算机基础考试题库大全
  19. linux irc 客户端,IRC 频道与客户端
  20. Linux内核之IO4:块I/O流程与I/O调度器

热门文章

  1. 头插法和尾插法创建单链表
  2. SQL 行转列 列转行 case when 写法
  3. php数字签名算法,PHP生成ECDSA算法数字签名
  4. 一个在台积电工作3年的工程师写给学弟学妹们的信
  5. FTP客户端,Windows端有哪些FTP客户端软件值得推荐?
  6. java毕业设计_校园外卖跑腿系统
  7. magaface 人脸识别测试
  8. 基于AI智能视频分析技术的电力行业视频监控联网解决方案
  9. fitnesse学习历程1
  10. JCommander(命令行参数解析工具)