前边OkHttp的源码顺藤摸瓜,摸了个遍。但是我们用的比较多的还是Retrofit,都是square的佳作,它是在OKHttp上进行了封装,对开发者变得更加友好。本文基于retrofit: 2.9.0开撸。
一、Retrofit在OKHttp上新增了什么魔法
- 使用动态代理模式使用接口和注解方式定义请求方法,对应用层友好,使用容易理解和方便
- 它可以和RxJava配合使用,超级解耦
- 它可以定制很多解析转换器,来将接口返回的数据封装为我们的JavaBean对象
- 在请求回来后,它会自动切换为主线程,无需额外在应用内部进行线程的切换
二、Retrofit的基本用法
Retrofit用法其实也不用多讲,很简单:
- 首先,新建个请求接口类
interface TestRetrofitService {
@GET("test")
fun getTestParms(): Call<ResponseBody>
}
- 再构建一个全局的Retrofit实例,它也是基于建造者模式
var retrofit: Retrofit = Retrofit.Builder().baseUrl("http://www.baidu.com").build()
- 然后使用Retrofit实例动态生成一个请求接口的代理对象
var testRetrofitService: TestRetrofitService = retrofit.create(TestRetrofitService::class.java)
*4. 使用代理对象调用请求接口方法,生成一个Call对象
val testCall: Call = testRetrofitService.getBaiduParms();
- 调用Call的enqueue方法,发起异步请求,execute方法则是同步请求
testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
TODO("Not yet implemented")
}
})
三、Retrofit是如何通过建造者模式实例化的?
Retrofit.Builder().baseUrl("http://www.baidu.com").build()
- Retrofit有个Builder内部类,它有两个构造方法,它会传入平台类,并通过jvm虚拟机的名字判断是Android平台还是Java平台。
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
private static Platform findPlatform() {
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android() //
: new Platform(true);
}
- 然后通过Retrofit.Builder实例可以传入很多配置参数,这和OKHttp一致,最后通过build()方法,实例化Retrofit
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
...
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
四、Retrofit是如何通过动态代理实例化请求接口类的代理对象?
//请求接口类
interface TestRetrofitService {
@GET("meinv")
fun getBaiduParms(): Call<ResponseBody>
}
//通过动态代理实例化一个代理对象
var testRetrofitService = retrofit.create(TestRetrofitService::class.java)
跟踪Retrofit.create()方法,映入眼前的就是妥妥的动态代理模式了,Proxy.newProxyInstance()。通过动态代理返回了一个TestRetrofitService接口类的代理对象
public <T> T create(final Class<T> service) {
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
...
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
158行 return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
五、Retrofit生成的动态代理对象调用请求方法后,如何返回的Call对象的?
val testCall: Call = testRetrofitService.getBaiduParms();
- 我们可以看到上面动态代理158行,这里又是Android和java平台的判断,这里直接可以看到
loadServiceMethod(method).invoke(args)
- 在loadServiceMethod()方法中,它将对传入的Method的注解进行解析保存为一个ServiceMethod对象并缓存起来。
ServiceMethod<?> loadServiceMethod(Method method) {
//1. 首先冲缓存中获取,获取到了就返回
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
//2. 为了线程安全问题,加了锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//3. 开始解析Annotations
result = ServiceMethod.parseAnnotations(this, method);
//4. 将解析好的serviceMethod缓存起来
serviceMethodCache.put(method, result);
}
}
return result;
}
- ServiceMethod是一个抽象类,HttpServiceMethod为其子类
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
26行 RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 如上26行,它通过RequestFactory类的parseAnnotations()方法解析请求接口类的方法上和参数的注解。
在RequestFactory里实际也是通过建造者模式,返回了RequestFactory实例
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
通过查看Builder内部类中的build方法,发现了很多解析Annotation注解的方法。
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
181行 parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
205行 parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
...
return new RequestFactory(this);
}
181行解析的是方法上的注解:这里大家看着都懂,无非就是解析方法上的一个@GET、@POST等注解,并获取值,并保存在成员变量中
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);
}
...
}
205行解析的是方法上的注解:这里就是将方法里的每个参数单独保存为一个ParameterHandler实例
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
...
}
后续的如何解析,大家可以深入代码中看看,这里就不一一贴代码了。比较简单,就是注解的解析取值,存值过程。
- 前边的ServiceMethod.parseAnnotations()方法最终返回了一个HttpServiceMethod实例,而HttpserviceMethod是ServiceMethod的子类
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
...
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 回到第2点,动态代理最终返回的是loadServiceMethod(method).invoke(args),而loadServiceMethod(method)返回的是一个HttpServiceMethod的实例,我们看看它的invoke()方法,这里就实例化了一个OKHttpCall对象,而它就是Call的子类。这里其实它还被另外一个ExecutorCallbackCall包装了一层(adapt(call, args)方法包装)。这里先不讲。
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
六、Retrofit如何通过Call实例对象发起请求的?
testCall.enqueue(object: retrofit2.Callback<ResponseBody>{
override fun onFailure(call: retrofit2.Call<ResponseBody>, t: Throwable) {
TODO("Not yet implemented")
}
override fun onResponse(call: retrofit2.Call<ResponseBody>, response: retrofit2.Response<ResponseBody>) {
TODO("Not yet implemented")
}
})
前面知道了其实真正执行请求的Call就是OKHttpCall,我们跟踪enqueue()方法进去看看。
- 调用OKHttpCall.enqueue()方法
@Override
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
synchronized (this) {
call = rawCall;
if (call == null && failure == null) {
try {
130行 call = rawCall = createRawCall();
} catch (Throwable t) {
}
}
}
147行 call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
callback.onResponse(OkHttpCall.this, response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callback.onFailure(OkHttpCall.this, e);
}
});
}
- 它在130行调用了createRawCall()方法,它调用了callFactory.newCall方法创建出okHttp3.Call对象
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
...
return call;
}
- 这里的callFactory实际上就是OKHttpClient,这在之前建造者模式创建Retrofit实例的build()方法中可以看到,而OkHttpClient.newCall()方法实际上就是返回了一个RealCall对象
public Retrofit build(){
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
}
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
- requestFactory.create(args)方法呢,就是返回了一个Request请求对象。
okhttp3.Request create(Object[] args) throws IOException {
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
...
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
...
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
- 回到1中的147行,call.enqueue()实际就是使用OKHttp的ReallCall对象开始将请求进行分发,或加入执行队列或加入等待队列。这里和之前写的《OKHttp源码解析》请求流程一致了。然后在回调接口。
七、Retrofit如何在返回response时,切换到主线程可以直接渲染UI的?
这里讲起来有点绕:
- 先回到Retrofit的创建来,在Build.buid()方法中,它会为Retrofit默认添加平台默认的CallAdapter适配器工厂,如android平台就添加Android类中的callbackExecutor(PS: Android是platform的子类,实现了defaultCallbackExecutor方法)
public Retrofit build() {
...
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
631行 callbackExecutor = platform.defaultCallbackExecutor();
}
638行 callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
...
}
- 631行获取了平台默认的回调执行器,这里就是线程切换的地方,而Android是Platform内部子类。它返回了一个MainThreadExecutor()对象,而它实际上就是通过new Handler(Looper.getMainLooper()),Handler来实现切回主线程。
static final class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
八. 实际上这里已经知道Retrofit怎么切换到主线程了,那么它在哪里调用的呢?
- 在 上面七的638行,platform.defaultCallAdapterFactories(callbackExecutor)它通过传入callBackExecuter,返回了一个平台默认的CallAdapterFactory适配器工厂。它实际上就是返回了一个DefaultCallAdapterFactory。
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
return hasJava8Types
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
- 前边我们说在HttpServiceMethod.invoke()返回的是一个OKHttpCall对象,其实不完全对,因为它还被CallAdapter适配器包装了一层。
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
- 2中所说的CallAdapter适配器就是通过DefaultCallAdapterFactory工厂的get()方法生成的。
至于如何生成,给一个路线(是在动态代理生成代理对象,并通过代理对象调用请求方法时):
- 2中所说的CallAdapter适配器就是通过DefaultCallAdapterFactory工厂的get()方法生成的。
1. ServiceMethod.parseAnnotations()
2.HttpServiceMethod.parseAnnotations()
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
3. HttpServiceMethod.createCallAdapter()
4. Retrofit.callAdapter()
5. Retrofit.nextCallAdapter()
public CallAdapter<?, ?> nextCallAdapter(
CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
...
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
return adapter;
}
}
- 看到DefaultCallAdapterFactory.get()方法,它返回了一个CallAdapter对象。
public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
...
47行 final Executor executor =
Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
? null
: callbackExecutor;
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);
}
};
}
- 47行:callbackExecutor实际就是1中的MainThreadExecutor,最后return CallAdapter,在CallAdapter的adapt方法中返回了一个ExecutorCallbackCall对象
new ExecutorCallbackCall<>(executor, call)
- 这个传入的参数call就是OKHttpCall, 而ExecutorCallbackCall就是包装OKHttpCall的,它主要用来回调时做线程切换用途的。它也是call的子类。它是DefautlCallAdapterFactory内部类
static final class ExecutorCallbackCall<T> implements Call<T> {
@Override
public void enqueue(final Callback<T> callback) {
//1. delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
delegate.enqueue(
new Callback<T>() {
@Override
public void onResponse(Call<T> call, final Response<T> response) {
//2. 请求返回后使用MainThreadExecutor对象切换线程
callbackExecutor.execute(
() -> {
if (delegate.isCanceled()) {
// 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));
}
});
}
}
- delegate就是OKHttpCall,实际上就是OKHttpCall.enqueue()
- 请求返回后使用MainThreadExecutor对象切换线程
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
九、结语
我们通过Retrofit的主线了解清楚了,Retrofit如何通过动态代理和注解反射等机制对OKHttp进行封装。对于我们灵活使用Retrofit来开发和解决使用Retrofit中遇到的问题非常有帮助,另外也通过跟踪框架源码,对于搭建框架也有了更多的认识和理论支撑。
网友评论