分析源码之前先介绍几个Retrofit中的概念。
Call,Request,Response,因为Retrofit中也是使用OkHttp来进行网络请求的,这几个概念和OkHttp中的基本类似,可以看下我在OkHttp源码分析一篇中开头对这几个概念的介绍。
CallAdapter<R, T>
Adapts a {@link Call} with response type {@code R} into the type of {@code T}.
将一个返回类型为R的Call适配为一个T。
Retrofit默认的为Call类型,比方说如果我们将Retrofit和RxJava结合使用,需要返回RxJava的Observable类型,那么我们就要提供相应的CallAdapter来将Call转化为Observable。
Converter<F, T>
Convert objects to and from their representation in HTTP.
将F类型转换为T类型。
主要用途是将原始请求参数的类型转换为okhttp3.RequestBody,以及将okhttp3.ResponseBody转换为你想要的返回类型。
本篇使用的Retrofit版本是2.4.0,上代码,一个Retrofit请求。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestApi request = retrofit.create(RequestApi.class);
retrofit2.Call<JSONObject> call = request.getCall(word);
call.enqueue(new retrofit2.Callback<JSONObject>() {
@Override
public void onResponse(retrofit2.Call<JSONObject> call, retrofit2.Response<JSONObject> response) {
if (200 == response.code()) {
JSONObject result = response.body();
}
}
@Override
public void onFailure(@NonNull retrofit2.Call<JSONObject> call, Throwable t) {
System.out.println("请求失败");
System.out.println(t.getMessage());
}
});
RequestApi类
public interface RequestApi {
@POST("translate?doctype=json&jsonversion=&type=&keyfrom=&model=&mid=&imei=&vendor=&screen=&ssid=&network=&abtest=")
@FormUrlEncoded
Call<JSONObject> getCall(@Field("i") String targetSentence);
}
首先,使用建造者模式完成Retrofit的构建。
然后调用Retrofit的create方法构建了RequestApi对象,我们看一下create方法。
public <T> T create(final Class<T> 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 {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
这是一个动态代理。
接着,使用代理生成的RequestApi对象调用getCall方法构建Call<JSONObject>对象。我们来分析一下这个动态代理内部是如何生成Call<JSONObject>对象的。
第一步调用loadServiceMethod方法来构建了一个ServiceMethod对象。下图截取了ServiceMethod类中的域和主要方法。
它的主要作用是将一个接口方法的调用适配为一个http请求。
它的创建使用的也是建造者模式。静态类Builder的build方法里面会把我们写在接口的请求方法里面的各种注解进行解析并且转化ServiceMethod对象相应的域。
然后是一个toCall方法,使用ServiceMethod对象的域来创建一个okhttp3.Call,最终会使用该Call来进行网络请求。
我们来看下他的Builder的build方法。方法比较长,我省略了好多不重要的代码,并且对每一段是干啥的加了注释。
public ServiceMethod build() {
//创建CallAdapter
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
//创建返回结果转换的Converter
responseConverter = createResponseConverter();
//解析方法上的注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
//解析参数上的注解
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);
}
...
return new ServiceMethod<>(this);
}
看看创建CallAdapter的createCallAdapter()方法。
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
...
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);
}
}
这里的method就是我们调用的接口中的相关请求方法,在我们上面的代码中就是getCall方法。将它的类型和方法注解传入retrofit的callAdapter方法来获取合适的CallAdapter。
跟进retrofit的callAdapter方法,发现它调用了nextCallAdapter方法。
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是一个CallAdapter的工厂列表,代码里面的逻辑是,在callAdapterFactories中依次进行遍历,第一个符合条件的将被返回。
我们在创建Retrofit对象的时候可以向callAdapterFactories添加工厂,比如如果我们将RxJava和Retrofit联合使用,想在interface方法中定义Observable作为返回类型,就需要添加第三方库中的RxJava2CallAdapterFactory。
Retrofit的build代码中添加了一个默认的DefaultCallAdapterFactory,它响应的类型是Retrofit的Call接口,所以如果我们不添加任何额外的CallAdapterFactory,那么interface方法中定义的返回类型只能为Call类型。
下面再来看创建返回结果转换Converter的createResponseConverter方法。
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
调用了Retrofit的responseBodyConverter方法,跟进去,发现调用了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) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
}
这个和获取CallAdapter的逻辑简直一模一样。converterFactories是一个Converter.Factory列表,一次遍历选取第一个符合条件的进行返回。
再看解析方法注解的方法parseMethodAnnotation
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) {
...
}
调用了parseHttpMethodAndPath方法,根据不同的注解类型传入不同的参数。
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
在这里解析出来httpMethod,hasBody,relativeUrl,relativeUrlParamNames等参数。
解析参数注解的部分,和解析类注解的部分相似,会根据参数上的注解的不同,生成不同的参数处理器保存到了parameterHandlers域中。
ServiceMethod的Builder的build方法主要做的事情就是这么多了,build方法结束之后,其构建的ServiceMethod对象中的域就都被赋值完成了。
我们再回到之前的动态代理的方法,看看ServiceMethod构建完成之后,构建的OkHttpCall是个啥。
final class OkHttpCall<T> implements Call<T> {
...
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
...
}
嗯,OkHttpCall实现了Retrofit的Call接口,但是其内部持有一个okhttp3.Call
,调用网络请求方法,实际是调用的okhttp3.Call的网络请求方法。
构建完OkHttpCall之后,调用了serviceMethod.adapt(okHttpCall)来返回指定的返回类型,也就是我们代码里面的retrofit2.Call<JSONObject>对象。
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
这个callAdapter的来历我们在ServiceMethod的build方法里面已经分析过了。由于我们的返回类型是retrofit2.Call<JSONObject>,所以这里的callAdapter会是默认的DefaultCallAdapterFactory返回的CallAdapter
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@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 call;
}
};
}
}
如上所示,DefaultCallAdapterFactory中返回的CallAdapter的adapt方法,只是简单地把传入的Call返回了,什么都没做。
所以我们在动态代理中返回的retrofit2.Call<JSONObject>的实际类型就是传入的OkHttpCall。
到这里,动态代理的代码就分析完了。
再来看看下一步,执行网络请求call.enqueue。
由于这里的call就是OkHttpCall,我们再来OkHttpCall的enqueue方法。
@Override
public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
...
call = rawCall = createRawCall();
...
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
...
response = parseResponse(rawResponse);
...
callback.onResponse(OkHttpCall.this, response);
...
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
...
});
调用了createRawCall方法来创建一个okhttp3.Call,然后调用该okhttp3.Call的enqueue方法。
继续跟进createRawCall方法
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.toCall方法
/** Builds an HTTP request from method arguments. */
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;
...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
使用了ServiceMethod之前解析出来的参数,比如httpMethod, baseUrl, relativeUrl, headers等等,构建了一个RequestBuilder对象,又使用RequestBuilder对象build出了一个okhttp3.Request对象,进而又构建出一个okhttp3.Call对象。这样,最终就是调用创建的这个okhttp3.Call来进行网络请求的。
可以看到,Retrofit对我们写在接口中的各种注解进行解析,得出请求参数,然后用这些参数构造出okhttp请求来请求网络。同时,它通过CallAdapter可以实现和RxJava的配合使用,通过Converter可以灵活地返回你需要的数据类型。