Retrofit无疑是一个成功的网络框架,它本身并不执行网络请求,而是给我们留下了很多网络封装的想象空间,这也是它的成功之处。
接下来,我们通过一个简单的网络请求,来看看它的内部是怎么设计的。
基于retrofit:2.9.0
Retrofit的使用
在这一节,我们写一个网络请求示例,以用来进行源码分析。如下所示
//首先定义一个WanAndroidService
interface WanAndroidService {
@GET("banner/json")
fun banner(): Call<Banner>
}
//进行Retrofit初始化
val retrofit = Retrofit.Builder()
.baseUrl("https://www.wanandroid.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
//进行请求
val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner().enqueue(object : Callback<Banner> {
override fun onResponse(call: Call<Banner>, response: Response<Banner>) {
}
override fun onFailure(call: Call<Banner>, t: Throwable) {
}
})
在此先感谢鸿神提供开放API,这里展示的是请求wanAndroid网站的banner,并且添加了GsonConverterFactory解析功能。
Retrofit原理
步骤1:Retrofit#create()
为什么不从Retrofit.Builder()初始化开始呢?因为Retrofit.Builder是一些配置条件,最终会呈现在Retrofit实例中。
这里贴一下Retrofit#create()的部分源码
public <T> T create(final Class<T> service) {
return (T)
//代码1
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
args = args != null ? args : emptyArgs;
//代码2
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
其中省略了一些校验逻辑,并不影响我们走流程。
首先来看看代码1,我们遇到了Proxy.newProxyInstance(),这便是Retrofit的设计理念之一,动态代理,想必很多人都已经听过了。动态代理平时开发中不怎么用到,这里提一嘴它的用处。
我们有一个interface A,那如果我要实现它,方法之一就是
class B implements A
那我觉得这样太麻烦了,可不可以不编写class B,在运行时创建interface A的示例呢,动态代理就出场了,这里动态和静态是相对的,class B可理解为静态
编写动态代理的方式就是Proxy.newProxyInstance(),传入需要代理的classLoader,interface,以及InvocationHandler,这里的InvocationHandler可理解为接口A的动态实例。
InvocationHandler的invoke()方法可以理解为对接口中方法的解析
关于动态代理的使用其实并不复杂,我们主要能理解InvocationHandler#invoke()即可。Retrofit#create()的方法,到这里就结束了,它就是返回了一个动态代理对象。
那当我们进入到InvocationHandler#invoke()方法的时候,其实代码已经走到了
val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner()
只不过,我们还没有调用enqueue()方法
我们调用service.banner()时,就已经来到了代码2
platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args)
这里是一个条件判断,platform.isDefaultMethod(),用来判断是否是默认的接口实现,这是Java8的特性,很显然我们定义的WanAndroidService#banner()并没有默认实现。
那么就会调用loadServiceMethod()方法,接着来看
步骤2:Retrofit#loadServiceMethod()
ServiceMethod<?> loadServiceMethod(Method method) {
...缓存逻辑
result = ServiceMethod.parseAnnotations(this, method);
...缓存逻辑
return result;
}
在删除缓存逻辑之后,可以看到执行ServiceMethod#parseAnnotations()方法,得到了一个result。我们继续跟进
步骤3:ServiceMethod#parseAnnotations()
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//代码1
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...校验逻辑
//代码2
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
在删除部分校验逻辑逻辑之后,值得一看的有两个方法,先来看代码1。
步骤4:RequestFactory#parseAnnotations()
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
这里直接调用了Builder,然后直接构造出了一个RequestFactory实例,那我们来看看在build()方法里做了什么。
步骤5:RequestFactory#build()
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
//代码1
parseMethodAnnotation(annotation);
}
....
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
//代码2
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
这个方法,我们大致看一下就好,主要是一些判断条件,比如代码1,parseMethodAnnotation(),主要是对我们定义的方法的注解进行解析,比如说我们定义的@GET注解,标记它是个GET方法,这里简单贴了一下代码
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
...
}
...
}
包括代码2,parseParameter()进行参数的解析,也包括参数的注解,比如我们例子中没有的@Query注解。
build()方法在这些解析方法之后就结束了,并将这些信息全部封装到一个RequestFactory实例中。到这里,我们就结束了步骤3中代码1的逻辑。让我们来到步骤3的代码2
步骤6:步骤3的代码2-HttpServiceMethod#parseAnnotations()
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
//代码1
adapterType = method.getGenericReturnType();
...
//代码2
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
...
//代码3
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
...
//代码4
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
...
}
这是很关键的一个步骤,在精简了代码之后,可以看到它的逻辑。代码分为4步,我也将各个步骤的逻辑罗列出来了
- 获取方法的返回值
- 根据返回值匹配CallAdapter
- 将返回值类型传给Converter,从而构建出合适的Converter实例
- 返回CallAdapted实例
接下来,我们一步一步分析。
步骤7:步骤6的代码1 - method.getGenericReturnType()
我们来分析一下步骤6的代码1
这里调用的是与Java反射相关的方法,获取对应方法的返回值类型,我们示例代码中就一个方法,这里贴一下
interface WanAndroidService {
@GET("banner/json")
fun banner(): Call<Banner>
}
可以知晓method指的是banner()方法,那method.getGenericReturnType()这个返回值就是Call,而不是Banner
步骤8:步骤6的代码2 - HttpServiceMethod#createCallAdapter()
紧接着来分析步骤6的代码2
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
...
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
}
可以看到,在内部调用了retrofit.callAdapter()方法,让我们再回到Retrofit类
步骤9:Retrofit#callAdapter()
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
//由于skipPast是null,那么start = 0
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;
}
}
...异常信息
}
这也是比较重要的代码,在callAdapter()方法内部调用了nextCallAdapter()方法,可以看到,nextCallAdapter()第一参数为null的目的是遍历所有的CallAdapterFactory,如果匹配到了,就返回对应的CallAdapter。这里最终匹配的是DefaultCallAdapterFactory,因为我们没有自定义CallAdapterFactory,所以这里返回的是默认的CallAdapterFactory,调用DefaultCallAdapterFactory的get()方法后获取到了它的一个匿名对象DefaultCallAdapterFactory$CallAdapter()
关于callAdapterFactories初始化,以及Retrofit默认的CallAdapterFactory文末会有交代,这里先走流程。
到这里,步骤8,也就是步骤6的代码2也分析完了,接着来看步骤6的代码3
步骤10:步骤6的代码3 - HttpServiceMethod#createResponseConverter()
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
...
return retrofit.responseBodyConverter(responseType, annotations);
}
这块代码和步骤8很相似,不过步骤8是获取CallAdapter,这里是获取Converter。一个是请求,一个是结果转换,实际上他们的代码逻辑是一样的。我们再次来到Retrofit类
步骤11:Retrofit#responseBodyConverter()
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
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;
}
}
}
这里就不解释了,和查找CallAdapter的逻辑是一样的。
不过不一样的是,我们添加了一个自定义的GsonConverterFactory,所以调用的是GsonConverterFactory#responseBodyConverter()方法,返回的是GsonResponseBodyConverter(),那如果我不自定义呢?默认是什么,同样在文末交代。我们接着走流程,那么到这里步骤6代码3就已经结束了。
步骤12:步骤6的代码4 - new CallAdapted()
在这一步骤,我们来给已经获取到的这些关键信息搞个封装。
//步骤6代码4
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
可以看到调用CallAdapted构造方法,这里CallAdapted是什么呢?其实是HttpServiceMethod$CallAdapted。
它的构造中传入的各个参数,我们一一列出来
- requestFactory是请求信息的封装,来源于步骤5
- callFactory是OkHttpClient对象,上文没有交代,我会在文末交代
- responseConverter是步骤11的GsonResponseBodyConverter()
- callAdapter是DefaultCallAdapterFactory$CallAdapter(),步骤9可知
到此,步骤6完结。然后步骤3结束,步骤2结束,我们最终返回CallAdapted实例。
注意:这里以“call”开头的类和对象比较多,其实不一样,要区分来源
步骤13:步骤1的loadServiceMethod().invoke()
到步骤12,还没有结束,我们在步骤1中分析完loadServiceMethod()返回CallAdapted实例,还需要调用invoke()方法。那我们就来看看具体方法
步骤14:CallAdapted#invoke()
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
其实这个invoke()方法并不属于CallAdapted(),而是属于他的父类HttpServiceMethod,CallAdapted既是HttpServiceMethod内部类,又是HttpServiceMethod的子类,CallAdapted结构如下。
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT>
我们接着来看invoke()方法。就两行代码,很简单。
- OkHttpCall初始化
- 调用adapt()方法,传入OkHttpCall实例
那,我们来看看adapt()方法
步骤15:CallAdapted#adapt()
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
在CallAdapted的父类HttpServiceMethod中,adapt()是一个抽象方法,交给子类CallAdapted实现。这里可以看到,继续调用了callAdapter的adapt()方法,OkHttpCall()对象继续作为参数传入,由步骤12可知callAdapter是DefaultCallAdapterFactory$CallAdapter对象,那我们接着来看
步骤16:DefaultCallAdapterFactory$CallAdapter#adapt()
//代码1
final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
//代码2
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
步骤9提到过的匿名对象在这里展现出来。看代码2,它的adapt()方法表明返回值与executor有关。那executor是不是空呢?
我们来看代码1,其中
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
这行代码的意思是annotations中有没有包含SkipCallbackExecutor对象,很显然,我们没有使用带有SkipCallbackExecutor的注解。所以这里是false,继而代码2处返回值为new ExecutorCallbackCall()。
到这里步骤14和13也结束了,我们得到了ExecutorCallbackCall()对象。接下来再回看步骤1
return loadServiceMethod(method).invoke(args)
这行代码的返回值是ExecutorCallbackCall()对象,这个返回值是动态代理的结果,也就是
val service: WanAndroidService = retrofit.create(WanAndroidService::class.java)
service.banner()
service.banner()的返回值。
接下来应该进入enqueue(...)流程了。
步骤17:ExecutorCallbackCall#enqueue()
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) {
//代码1
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
//代码2
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
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(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
....
}
ExecutorCallbackCall是Call对象的子类,从代码1中可以看到,并不是ExecutorCallbackCall本身执行enqueue()方法,而是通过delegate执行enqueue(),这个delegate从构造方法中来,那么我们从步骤14,步骤15,步骤16可以得知,这个delegate是OkHttpCall。
那我们再来到OkHttpCall的enqueue()看看
步骤18:OkHttpCall#enqueue()
@Override
public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
...
call = rawCall = createRawCall();
...
//代码1
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
...
//代码2
response = parseResponse(rawResponse);
...
//代码3
callback.onResponse(OkHttpCall.this, response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
callback.onFailure(OkHttpCall.this, e);
}
});
}
到这里总算是守得云开见月明了,代码1中call.enqueue()这里的call已经是okhttp3.Call的Call对象了,调用enqueue()表示网络请求放在子线程执行,okhttp的onResponse回调也是在子线程。接着代码2,解析rawResponse,也就是原始的Response,代码2稍候再细看,接着代码3回调,也是子线程。
再回到步骤17,Callback在子线程怎么办?Retrofit可是在主线程回调的,不急,继续往下看
步骤19:步骤17代码2-callbackExecutor.execute()
步骤17中的代码2有一个callbackExecutor,这是什么呢?我们看到这个callbackExecutor是在ExecutorCallbackCall构造方法中传入的,其实这是Retrofit在Android平台提供的MainThreadExecutor,这里先按下不表,同样看文末。
那我们就来看看这个MainThreadExecutor
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
很简单,execute()方法就是切主线程,所以步骤17代码2,成功切换到了主线程。
到这里逻辑已经梳理完毕了。
我们再回过头看看,留下了哪些问题。
问题1:步骤18代码2的parseResponse()还没解决呢
我们来看看怎么解析的
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
int code = rawResponse.code();
//代码1
if (code < 200 || code >= 300) {
}
if (code == 204 || code == 205) {
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
//代码2
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
}
代码1判断code,代码2执行解析,我们直接来看解析。
responseConverter是谁还记得吗?步骤12里讲过是GsonResponseBodyConverter,那直接来看代码
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
T result = adapter.read(jsonReader);
return result;
}
很简单,就是Gson解析。
问题2:Retrofit默认的CallAdapterFactory怎么来的,默认的Converter是什么,callFactory为什么是OkHttpClient对象,MainThreadExecutor在哪里初始化
这些问题之所以放在一起,是因为他们初始化的时机都差不多。
来看下Retrofit#build()方法
public Retrofit build() {
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
//默认的callFactory是OkHttpClient(),因为我们没有自定义OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//代码1
callbackExecutor = platform.defaultCallbackExecutor();
}
//我们自定义的callAdapterFactories,这里是空
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
//代码2 默认的callAdapterFactories
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//代码3 默认的ConverterFactories
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
代码1,2,3都与platform有关,这个Platform是平台,接下来再来看看Platform类
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//这里指定了Android平台
private static Platform findPlatform() {
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android()
: new Platform(true);
}
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
//默认的DefaultCallAdapterFactory
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
//Android平台代码
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override
public Executor defaultCallbackExecutor() {
//线程调度
return new MainThreadExecutor();
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
}
现在只剩下一个问题,默认的Converter是什么?
虽然在Retrofit#build()中有指定defaultConverterFactories以及默认的BuiltInConverters,但其实我们去掉GsonConverterFactory后会报错在步骤10。原理跟匹配CallAdapterFactory一样,没有匹配到对应的Converter。
Could not locate ResponseBody converter for class com.example.test.Banner
在文章中我省略了很多代码,有兴趣的同学可以自行查看。