Retrofit是Square公司出品的Http请求框架,底层网络模块基于Okhttp,是构造REST风格的HTTP客户端的利器,同时具备非常强大的解耦性,可以自定义多种数据格式(xml、json、protocol buffers等),支持Rxjava调用方式。
最近一直在看Retrofit2的源码,对于它具体的流程也是在多次调试后,才略微一二。下面主要分析下Rxjava接口形式的接口生成和调用流程。
Retrofit
Retrofit类是整个流程的入口通过它的Builder类设置一些基本的参数,如下:
new Builder().baseUrl(baseUrl).addConverterFactory(factory).addCallAdapterFactory(RxJavaCallAdapterFactory.create());
ConverterFactory是Request和Response的转换类,继承Factory类,实现responseBodyConverter和requestBodyConverter即可。guava、gson、java8、protobuf等各种格式的converter可以参考官方文档。
Retrofit#create
通过create(final Class<T> service)方法,将注解定义的接口生成一个具体的接口实现。接口定义方式如下:
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
如果使用Rxjava的话,可以定义如下:
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
具体的create方法代码如下:
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(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, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
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);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
它通过Proxy.newProxyInstance方法来一个实现了我们定义好的API接口的动态代理类,之后调用任何接口里面的方法,都会通过调用invoke(Object proxy, Method method, Object... args)方法来实现。
ServiceMethod
invoke方法最重要的是最后三行代码。loadServiceMethod方法先会判断缓存里面有没有该method对应的ServiceMethod,如果有就直接用,没有就会生成一个新的。
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
下面看下ServiceMethod的生成过程。
Adapts an invocation of an interface method into an HTTP call.
ServiceMethod 的作用就是把一个 API 方法转换为一个 HTTP 调用。
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
以上面的GitHubService中listRepos接口为例。
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
@GET("users/{user}/repos"是methodAnnotations,String是parameterTypes,@Path("user")是parameterAnnotationsArray的第一个,参数可以有多个,所有它是一个列表。
ServiceMathod#Builder.build()
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
上面是build方法里面去除了异常处理之后的逻辑。
createCallAdapter
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
return retrofit.callAdapter(returnType, annotations);
}
retrofit.callAdapter里面主要代码:
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
它根据returnType和annotations遍历adapterFactories,获取合适的CallAdapter。
/** * Returns an instance of {@code T} which delegates to {@code
call}. */ <R> T adapt(Call<R> call);
它的作用就是把 retrofit2.Call<R> 转换成我们需要的 T,目前retrofit2.Call的实现只有OkHttpCall,所以现在Retrofit网络框架只能用OkHttp。CallAdapters
createCallAdapter
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
return retrofit.responseBodyConverter(responseType,
}
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;
}
}
它最后也是遍历converterFactories,获取合适的ResponseConverter,它一般是自定义的,通过Retrofit的Builder类addConverterFactory(factory)方法添加的。
parseMethodAnnotation
DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS这些注解会调用parseMethodAnnotation方法,生成httpMethod、hasBody、relativeUrl、relativeUrlParamNames4个ServiceMethod的参数,当注解是retrofit2.http.Headers类型时,会调用parseHeaders方法,它会生成OkHttp的Headers。
parseParameter
parseParameter方法通过参数的注解和类型,生成对应的ParameterHandler。
ParameterAnnotation | ? extends ParameterHandler |
---|---|
Url | RelativeUrl |
Path | Path |
Query | Query |
QueryMap | QueryMap |
Header | Header |
HeaderMap | HeaderMap |
Field | Field |
FieldMap | FieldMap |
Part | Part |
PartMap | PartMap |
Body | Body |
所有类型的ParameterHandler都继承自ParameterHandler,实现了apply方法,通过Converter方法,把参数都转换成相应的类型,然后设置到RequestBuilder中,其中Part、PartMap、Body转成RequestBody,其他都转成String。
这样ServiceMethod基本构造完成。
OkHttpCall
之前我们说了,它是Retrofit中Call的唯一实现。
public interface Call<T>
它负责发起请求和回复,每个Call只负责一对请求和回复,如果要复用的话,调用Call.clone方法。Call主要有execute和enqueue方法,前者是同步的,后者是异步的。OkHttpCall实现了Call接口,里面使用okhttp3.Call来完成网络服务交互。
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call; }
createRawCall方法生成okhttp3.Call,request参数是通过serviceMethod的toRequest方法生成的。
execute和enqueue方法里面实际上就是调用okhttp3.Call来实现了同步和异步请求,但是对Response做了进一度处理,通过parseResponse方法,把OkHttp3.Response转成Retrofit2.Response
T body = serviceMethod.toResponse(catchingBody); return
Response.success(body, rawResponse);
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body); }
还是调用Retrofit里面的responseConverter实现了返回结果的转换。
serviceMethod.callAdapter.adapt(okHttpCall)
这一步是把Call转成我们所需的T。
CallAdapters | ? extends CallAdapter.Factory | T |
---|---|---|
guava | retrofit2.adapter.guava.GuavaCallAdapterFactory | com.google.common.util.concurrent.ListenableFuture |
java8 | retrofit2.adapter.java8.Java8CallAdapterFactory | com.google.common.util.concurrent.ListenableFuture |
rxjava | retrofit2.adapter.rxjava.RxJavaCallAdapterFactory | rx.Observable |
default | retrofit2.ExecutorCallAdapterFactory | retrofit2.Call<R> |
default | retrofit2.DefaultCallAdapterFactory | retrofit2.Call<R> |
如果是retrofit2.Call类型的,可以调用execute或者enqueue完成请求。
如果rx.Observable类型,会在subscribe()时候调用下面代码:
@Override public void call(final Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();
// Wrap the call in a helper which handles both unsubscription and backpressure.
RequestArbiter<T> requestArbiter = new RequestArbiter<>(call, subscriber);
subscriber.add(requestArbiter);
subscriber.setProducer(requestArbiter);
}
它其实是Observable.create(new CallOnSubscribe<>(call))里面CallOnSubscribe的实现。
网友评论