使用
使用一个官方的使用sample入手。
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
}
public static void main(String... args) throws IOException {
// Create a very simple REST adapter which points the GitHub API.
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
List<Contributor> contributors = call.execute().body();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
一、构建阶段
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
执行build,构建各种工厂,为后面做好准备
public Retrofit build() {
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
//不传递进来的话,自动创建一个
callbackExecutor = platform.defaultCallbackExecutor();
}
}
这里执行把retrofit.create(GitHub.class)的返回值赋值给了定义的网络请求接口,说明了返回值一定是实现了这个接口的对象。
GitHub github = retrofit.create(GitHub.class);
从整个方法来看,这是一个动态代理的使用。因为用户所定义的所有接口,都会触发InvocationHandler()的回调。正因如此,这是一个面向切面编程的思想的体现。
既然所有的接口执行都会跑到这里的代码,不妨先看loadServiceMethod(method)做了什么。
Retrofit.java
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
return loadServiceMethod(method).invoke(args);
}
});
}
Retrofit.java
ServiceMethod<?> loadServiceMethod(Method method) {
result = ServiceMethod.parseAnnotations(this, method);
}
return result;
}
ServiceMethod.java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
先看第一句代码,把retrofit, method作为参数传递进去,为的是通过反射拿到框架使用者定义的接口上面的所有注解和接口方法参数拿到,同时保存起来放到RequestFactory类中。
RequestFactory.java
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
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);
}
RequestFactory.java
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("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
接着回到ServiceMethod 的第二句代码,执行了:
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
这个方法主要创建了CallAdapter、Converter、 okhttp3.Call.Factory,接着把这三者和通过方法参数传进来的requestFactory一起作为构造参数new了CallAdapted对象。
HttpServiceMethod.java
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
}
到这里Retrofit.java中的 loadServiceMethod(method)方法算是执行完了。
总结下,就是把用户定义的网络请求接口的所有注解、参数保存到RequestFactory中,然后创建了CallAdapter、Converter、 okhttp3.Call.Factory,为后面代码的执行做好准备。
二、转换阶段
接着看下Retrofit类中loadServiceMethod(method).invoke(args)的invoke方法
ServiceMethod.java
abstract @Nullable T invoke(Object[] args);
这里可以很开心的看到,由于有上面第一阶段的准备的requestFactory, args, callFactory, responseConverter,在这里把它们组装成了一个OkHttpCall。
接着执行adapt(call, args)。
HttpServiceMethod.java
final @Nullable ReturnT invoke(Object[] args) {
//新建ServiceMethod的实现类
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
到这里会发现,实现这个接口的类有很多,通过前面build阶段可以确定,这里执行的是DefaultCallAdapterFactory.java
CallAdapter.java
T adapt(Call<R> call);
上面的loadServiceMethod(method).invoke(args)方法也就到此为止了。
可以看到,到这里new了一个ExecutorCallbackCall,而里面有个enqueue方法,看起来似乎就是执行网络请求的地方。
DefaultCallAdapterFactory.java
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
};
}
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) {
Objects.requireNonNull(callback, "callback == null");
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on
// cancellation.
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));
}
});
}
}
回头看调用方法,retrofit.create(GitHub.class)通过动态代理的方式创建了代理对象并存储在内存中。
而我们知道,在动态代理中,代理对象在调用代理方法的时候,会调用内存中代理对象的接口方法,而接口方法里面会调用InvocationHandler接口。知道这个点之后,再分析这个场景。
这里github.contributors(“square”, “retrofit”)的调用,调用到了内存中代理对象中实现的contributors方法,contributors方法里面又会调用InvocationHandler接口,最终触发了retrofit的create方法里的匿名内部类InvocationHandler的回调。所以,每个客户定义的接口在被动态代理执行的时候,最终都会新建一个InvocationHandler的匿名内部类,并且执行invoke方法的执行流程。
画个图帮助大家理解:
GitHub github = retrofit.create(GitHub.class);//ExecutorCallbackCall
Call<List<Contributor>> call = github.contributors("square", "retrofit");
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
return loadServiceMethod(method).invoke(args);
}
});
}
三、发起网络请求阶段
终于可以发起请求了
List<Contributor> contributors = call.execute().body();
execute接口的调用其实会调用到两个类的方法,首先看调用到的”假请求“
“假请求”:ExecutorCallbackCall
前面分析到:retrofit创建出动态代理对象的时候,只要一调用代理对象的代理方法,会调用到InvocationHandler方法来,而InvocationHandler方法里面的loadServiceMethod(method).invoke(args)方法会创建出一个ExecutorCallbackCall对象来。所以会调用到ExecutorCallbackCall的execute方法。但是这里的调用是调了个寂寞,真正发起的请求在哪呢?
retrofit2 Call.java
Response<T> execute() throws IOException;
DefaultCallAdapterFactory.java
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 Response<T> execute() throws IOException {
return delegate.execute();
}
}
“真请求“:OkHttpCall
再次回到retrofit2 Call的接口,发现实现了这个接口的还有OkHttpCall类,回顾前面分析到的代码,在前面retrofit其实以前new出了OkHttpCall的对象,原来是为了这里的调用而做好的准备!
通过接口调用的方式,调用到了OkHttpCall类里面,getRawCall方法会调用到createRawCall方法,而createRawCall方法里面的requestFactory也正好保存了准备阶段里面做好的接口上的各种注解参数和方法参数。接着便发起了OKhttp的网络请求,到这里为止,请求转给了OKhttp。
retrofit2 Call.java
Response<T> execute() throws IOException;
OkHttpCall.java
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
call = getRawCall();
}
return parseResponse(call.execute());
}
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
return call;
}
接着看return parseResponse(call.execute()),这里的接口Call是OKhttp的接口,parseResponse也就是解析OKhttp请求返回的数据。
responseConverter.convert方法便是把OKhttp返回的数据使用转换器进行转换。这也是为什么使用retrofit的时候,我们甚至连json转实体类的转换都不需要我们做的原因。
okhttp3 Call.java
Response execute() throws IOException;
OkHttpCall.java
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
}
}
至此一个网络请求执行完毕。