前言
本文主要是带着三个问题去理解Retrofit的工作原理;
- 1.我们调用定义好的接口后发生了什么,接口api到底是怎么解析出来的?
- 2.Retrofit是怎么和Okhttp合作的,因为发送请求最终都是Okhttp;
- 3.解析返回的数据怎么corvert成RxJava的observable的?
带着这三个问题,我们开始下面的讲解。
Retrofit的使用
public interface MedalApi {
String url = "employeeMedal/medalList.do";
@FormUrlEncoded
@POST(url)
Observable<AchievedMedalResult> getAchievedMedal(@Field("account") String account,
@Field("accountType") String accountType,
@Field("queryEmployeeId263") String queryEmployeeId263);
@GET(url)
Observable<AchievedMedalResult> testMedal();
@POST("/example_copy_copy/medallist")
Observable<AchievedMedalDetailResult> getAchievedMedalDetail(@Field("account") String account,
@Field("accountType") String accountType,
@Field("queryEmployeeId263") String queryEmployeeId263,
@Field("queryMedalCode") String queryMedalCode
);
}
public static <T> T createService(Class<T> service, String baseUrl) {
//日志处理
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
L.d(TAG, message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//.addInterceptor(new LoggerInterceptor("TAG"))
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
/* 关闭OkHttp失败重试连接的机制,该问题导致发帖重复的问题 */
.retryOnConnectionFailure(false)
.addInterceptor(loggingInterceptor)
.addInterceptor(new HttpHeadInterceptor())
.addInterceptor(new SecurityInterceptor(AppInstance.INSTANCE)) // 加密解密
.addNetworkInterceptor(new StethoInterceptor())
.dns(new SunlandDNS())
// 其他配置
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(service);
}
上面就是实际使用了,做一些简单配置就可以发送请求了,返回的数据是转换后好的实体类,确实很方便。
原理解析
上面简单讲了使用方法,下面开始进入正题,讲讲背后的原理。
Retrofit实例化
首先看看它是怎么被初始化的,就是入口在哪?很显然,就是那个build,建造者模式,这个和okhttp是异曲同工。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
}
它会接收一些外面传进来的参数,比如url,默认初始化okhttpclient,covert等,然后直接new了一个Retrofit,这才是把初始化的一些值真正保存到Retrofit对象里面去;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
这里面的参数都是非常重要的,有的是默认的,有的是外面初始化的时候传递进来的。
Retrofit的create()
好了retrofit实例有了,接着看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, @Nullable 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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
这里把我们定义好的api接口当做class参数传递进来,可以看到,这里面采用的是java动态代理技术,把接口api里面的方法集中在代理的invoke方法中去执行了,做了如下几件事
- 对method做校验,object默认的方法我们不用去管,直接执行。
- 对平台的校验,在java8中默认会做校验,android中,我们不用去理会。
- 重点的是最后三行代码,创建ServiceMethod,实例化OkHttpCall, serviceMethod.adapt。
接下来我们对最后三行代码做分析;
首先看loadServiceMethod :
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
serviceMethodCache里面存放的是Method和ServiceMethod的键值对,首先从map中去读取ServiceMethod,如果当前的值存在,那就直接使用。否者就需要新建ServiceMethod。这个逻辑是非常简单的,就是使用了缓存机制,因为java的动态代理和注解的解析都是比较耗时的,所以缓存是很有必要的。接下来看看ServiceMethod到底是何方神圣,需要我们大费周折的去获取或新建。 ServiceMethod的Build()
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
这里把retrofit和method当作参数传递过来,然后获取method里面的一些参数,是的,api接口看上去是很抽象的,里面有注解,参数类型,还有参数的注解等等,首先获取api里的这些参数,然后看看build();
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
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);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
这个方法看上去比较长,但是并不难,我们分步说明之:
- 1.创建calladapter,这个方法最终的创建过程是在retrofit中,例如创建RxJava的CallAdapter
- 2.创建responseConverter,返回结果的covert,这个最终也是在retrofit里面创建的,例如创建GsonConveter
- 3.查找method中的所有注解,并一个个解析出来,http的各种请求post,get,put等注解,都是在这里解析出来的。
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);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
}
- 4.对上面解析出来的注解做个校验,需要有httpmethod,也就是说必须要有请求方法的注解才行,否则会抛异常,这也很好理解,发请求肯定是要指明是post还是get吧。
- 5.对请求做一些其他的校验,比如post请求必须含有body等。再就是URL是否为空。
- 6.所有的校验通过以后,最后就是实例化了,如下:
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
好了,这个扯得有点多了,让我们还是回到那个代理类得invoke方法里面去。
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
这里实例化OkHttpCall,其中参数就是我们刚刚新建好的serviceMethod,这个call实质上就是okhttp里面的那个call,对的,最终调用网络请求就靠它了。 如果上面的都是准备工作的话,接下来才是正式开始发送请求了。这里我决定分两部分讲,一种是adapt返回普通的Call,另外一种返回RxJava的Observable,实质上这也是Retrofit的两种不同用法。
return serviceMethod.adapt(okHttpCall);
返回类型是Call的调用
adapt方法返回类型是有okhttpcall里面的servicemethod来决定的。OkHttpCall实现了Call,这里返回的是call,接下来就是执行请求了。请求的执行分同步和异步。 同步的请求方法是 call.execute();
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
发送请求的是rawCall;
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
继续跟
/** 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;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return callFactory.newCall(requestBuilder.build());
}
这个过程调用servicemethod的toCall方法去构建网络请求,返回okhttp3.call,之后再调用call里面的ececute(),最后调用parseResponse对返回的结果进行解析;这里解析就不做过多分析了。
接着看看异步的调用: 事实上了解同步以后,异步也就差不多了:
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(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 {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
就是把刚刚新建的request放到线程池里面去,然后使用callback对返回结果进行解析。以上就是普通的返回call的调用方法。
对于RxJava中的调用
我们使用的时候是怎么初始化的:
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
这里是使用的RxJava和GsonConvert,将它们保存在Retrofit的对象里面先存着,后面会用到。接着看ServiceMethod中build(),里面会调用createCallAdapter(),从字面意思可以理解为创建adapter; 最终会调用Retrofit中的函数:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
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不就是我们刚刚往里面addCallAdapterFactory值了的吗,没错,所以最终会调用RxJavaCallAdapterFactory的get方法
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
if (!(returnType instanceof ParameterizedType)) {
String name = isSingle ? "Single" : "Observable";
throw new IllegalStateException(name + " return type must be parameterized"
+ " as " + name + "<Foo> or " + name + "<? extends Foo>");
}
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
...
return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
false);
}
看重点,这个get方法经过一定处理后,最终会实例化一个RxJavaCallAdapter 对象,然后会去调用这个类里面的adapt方法。
@Override public Object adapt(Call<R> call) {
OnSubscribe<Response<R>> callFunc = isAsync
? new CallEnqueueOnSubscribe<>(call)
: new CallExecuteOnSubscribe<>(call);
OnSubscribe<?> func;
if (isResult) {
func = new ResultOnSubscribe<>(callFunc);
} else if (isBody) {
func = new BodyOnSubscribe<>(callFunc);
} else {
func = callFunc;
}
Observable<?> observable = Observable.create(func);
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isSingle) {
return observable.toSingle();
}
if (isCompletable) {
return observable.toCompletable();
}
return observable;
}
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
所以不同的callAdapter会调用不同的类中的adapt,返回的结果也不一样,前面说的默认的都是返回的call,RxJava返回的是Observable。然后就是使用Rxjava去发网络请求咯:
@Override public void call(Subscriber<? super Response<T>> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call<T> call = originalCall.clone();
CallArbiter<T> arbiter = new CallArbiter<>(call, subscriber);
subscriber.add(arbiter);
subscriber.setProducer(arbiter);
Response<T> response;
try {
response = call.execute();
} catch (Throwable t) {
Exceptions.throwIfFatal(t);
arbiter.emitError(t);
return;
}
arbiter.emitResponse(response);
}
}
里面的call.execute()就是执行网络请求的,这些就和前面没有区别了,最后会得到Respone,然后进行解析,这就讲清楚了怎么使用RxJava发送网络请求的,那么第二个问题,最终我们怎么把返回值转换为对应的Observable呢。接着看,分析方法类似于上面,在ServiceMethod的build中有
responseConverter = createResponseConverter();
这就是创建Convert,这个Convert就是初始化的时候传递进去的,我们传的是GsonConverterFactory,所以和adapter一样最终会走到Retrofit里面去:
{
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
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;
}
}
}
代码和分析adapter的差不多,最终会走到GsonConverterFactory
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
当Retrofit在解析Respone数据的时候会调用ServiceMothod的如下方法:
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
继续跟:
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
就是Gson将返回结果做了处理,直接convert成对象返回了,最后再封装成Observable。
总结
分析完后我们再来看看文章开头的三个问题,是不是都已经有结果了,最后我们上一张图,整个Retrofit的分析流程图:
