本文基于Retrofit版本:
com.squareup.retrofit2:retrofit:2.9.0
1-基本流程
Retrofit框架其实可以理解为OkHttp的第一个Interceptor,对OkHttp的请求及结果进行处理,符合RESTful规范的一个框架,同时也支持通过RxJava实现响应式编程,通过一系列的封装使得OkHttp用起来更方便。本文重点解析Retrofit部分原理,至于其核心的OkHttp部分前面的文章已经分析过了:读源码-OkHttp源码解析
1.1-创建Retrofit实例
通过Retrofit实现网络通信,第一步当然是初始化工作了。Retrofit和OkHttp的代码风格很像,同样采用建造者模式构建Retrofit实例:
Retrofit mRetrofit = new Retrofit.Builder()
.baseUrl("https://wanandroid.com/")
.addConverterFactory(JacksonConverterFactory.create())
.build();
逻辑很简单就是通过获取Retrofit的构造器Builder对象,创建Retrofit实例,并初始化一些配置项。我们直接看build方法中初始化了哪些配置项:
public Retrofit build() {
//baseUrl必须要配置,一般是服务端域名的scheme+host
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//创建OkHttpClient实例,通过OkHttp处理后续网络请求和响应
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//回调处理器,默认为null
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//设置网络请求适配器工厂类,默认CompletableFutureCallAdapterFactory
//可以设置成RxJava3CallAdapterFactory来支持RxJava3
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
//添加默认数据转换器工厂BuiltInConverters
converterFactories.add(new BuiltInConverters());
//添加自定义数据转换器工厂,例如设置JacksonConverterFactory,支持通过Jackson来解析数据
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(。。。//实参省略);
}
}
初始化过程中主要涉及到的配置项:
- baseUrl 必选,标识服务端地址的scheme+host
- callFactory 默认OkHttpClient,处理网络通信部分
- callAdapterFactories 默认CompletableFutureCallAdapterFactory,可以将OkHttpCall转换成适合不同平台来调用的网络请求
- converterFactories 默认BuiltInConverters,数据转换器工厂,BuiltInConverters直接取对应的值并未转换。可以通过设置JacksonConverterFactory来使用Jackson解析json数据,GsonConverterFactory来用Gson解析,如果要用FastJson需要继承Converter.Factory自定义数据转换工厂。
1.2-创建请求接口
创建网络请求接口,通过注解的方式写入要调用接口的url的后半部分,前半部分已在初始化时配置baseUrl。先看代码
public interface AppService {
//请求方法为GET,path=wxarticle/chapters/json
@GET("wxarticle/chapters/json")
Call<TextResponse> getAuthorList();
}
可以看到通过注解标注请求方法类型及请求url的后半部分,定义方法需要设定方法返回参数类型,根据服务端返回的数据格式自定义Data类。接口创建完后,通过Retrofit创建接口实例?对,实例的是继承该接口的代理类,Retrofit通过动态代理该请求接口来实现方法调用。
AppService mService = mRetrofit.create(AppService.class);//生成接口的动态代理对象
Call<TextResponse> call = mService.getAuthorList();//通过代理实现网络请求
接着看Retrofit.create是如何创建并实例化代理对象的。
public <T> T create(final Class<T> service) {
//@1.验证接口合法性,解析获取接口中的所有注解方法封装成ServiceMethod
validateServiceInterface(service);
//通过InvocationHandler实例化动态代理类
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果是Object可以访问的方法,直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
//默认方法,即public非静态方法,正常反射调用
//@2.非默认方法,获取对应ServiceMethod对象并调用invoke方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
@1.验证接口合法性,解析获取接口中的所有注解方法封装成ServiceMethod
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {//必须是接口
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
//验证接口泛型参数及接口类型
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
//如果设置了预解析,提前解析获取非默认方法列表并缓存,方法会封装成ServiceMethod对象
//动态代理对象也是通过调用loadServiceMethod来解析非默认方法并调用
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
//非静态默认方法
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
@2.非默认方法,获取对应ServiceMethod对象并调用invoke方法
ServiceMethod<?> loadServiceMethod(Method method) {
//优先从缓存中获取
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
//加锁后再次尝试从缓存中获取
result = serviceMethodCache.get(method);
if (result == null) {
//@3.解析该方法,获取注解信息构建请求Request
//构建请求对象及Http请求方法最终封装成HttpServiceMethod
result = ServiceMethod.parseAnnotations(this, method);
//缓存该方法
serviceMethodCache.put(method, result);
}
}
return result;
}
@3.parseAnnotations方法中
- 第一步:解析注解方法中的参数信息,例如1.2中定义的方法getAuthorList,解析后得到调用方法类型GET、请求域名path=wxarticle/chapters/json、响应数据类型TextResponse。根据这些信息创建Http请求Request的工厂类
- 第二步:将方法信息,Request工厂及Retrofit引用封装到HttpServiceMethod。1.2中的例子调用代理对象的getAuthorList()方法最终是调用了HttpServiceMethod对象的invoke方法来发起网络请求。
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//@4.第一步根据注解生成Request的工厂类
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//方法返回类型不能包含类型变量或通配符
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
//方法返回类型不能为空
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//@5.第二步,根据Request工厂类及Retrofit实例引用构建HttpServiceMethod对象,供代理对象调用发起网络请求
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
@4.第一步根据注解生成Request的工厂类。调用链路RequestFactory.parseAnnotations–>RequestFactory.Builder.build
RequestFactory build() {
//先解析Http 方法 get/post/delete等,对应例子中的GET方法
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
。。。//省略 Http 方法解析异常处理
//解析注解接口的入参,对应例子中的"wxarticle/chapters/json"
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);
}
。。。//省略 Http 请求参数解析异常处理
//将解析出来的参数生成RequestFactory实例
return new RequestFactory(this);
}
@5.第二步,根据Request工厂类及Retrofit实例引用构建HttpServiceMethod对象,供代理对象调用发起网络请求。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
。。。//Kotlin支持
} else {
//获取方法类型
adapterType = method.getGenericReturnType();
}
//获取CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
//根据CallAdapter获取response类型,默认Call<T>
//如果设置为RxJava3CallAdapter则返回Observalbe<T>
Type responseType = callAdapter.responseType();
。。。//省略responseType异常校验
//获取response body数据转换器。对应例子中JacksonConverterFactory.responseBodyConverter
//用于将response 的body转换成用户设置的数据类型
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
//将CallAdapter封装进去
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
。。。//kotlin检测
} else {
。。。//kotlin检测
}
}
1.3-请求及回调处理
前面创建了服务接口的代理对象,发起网络请求时通过代理对象调用HttpServiceMethod.invoke
@Override
final @Nullable ReturnT invoke(Object[] args) {
//生成OkHttpCall实例
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
//@6.发起请求
return adapt(call, args);
}
前面1.2最后HttpServiceMethod.parseAnnotations方法返回的是封装了CallAdapter的CallAdapted对象,所以adapt方法是CallAdapted中实现的。调用链路CallAdapted.adapt–>CallAdapter.adapt–>OkHttpCall.enqueue
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//创建OkHttp的Request对象,再封装成OkHttp.call
//这里用到了1.2章@4处创建的RequestFactory工厂类来创建Request
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
。。。//省略
//通过OkHttp发送网络请求
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//@6.解析OkHttp返回结果
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
//调用Call.onResponse回调,即最终结果回调
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
。。。//callFailure方法处理失败回调
});
}
@6.解析OkHttp返回结果。OkHttpCall.parseResponse
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();//获取OkHttp返回结果类型ResponseBody的对象
//获取响应体部分
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
。。。//根据相应状态码处理失败或异常情况
//创建ResponseBody的代理对象
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//通过初始化时设置的数据转换器来将OkHttp的response转换成接口方法的返回类型
//对应例子中的设置的JacksonResponseBodyConverter.convert方法
//通过代理对象catchingBody读取数据流转换成TextResponse对象
//将转换后的结果封装成Retrofit的Response类型返回,调用Call.onResponse回调
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
2-总结
通过Retrofit的简单实用分析完了其主要流程,内容是不是很少,Retrofit的核心就是其代码中用到的各种设计模式。总结下Retrofit的简单调用流程:
- 初始化Retrofit
- 创建请求接口Service
- 通过动态代理ServiceProxy调用HttpServiceMethod的invoke
- 生成OkHttp需要的 Request对象通过OkHttpCall发起网络请求
- 返回OkHttp类型的Response,通过Converter转换为返回参数类型T
- 回调Call.onResponse