现在安卓开发网络框架使用最多的就是Retrofit,今天就剖析下Retrofit的原理。
看看官网的介绍 (https://square.github.io/retrofit/#introduction)
A type-safe HTTP client for Android and Java 一种类型安全的HTTP客户端,适用于Android和Java平台。Retrofit通过注解实现RESTful网络接口,底层使用Okhttp完成网络请求的实现。另外,Retrofit封装了主线程和子线程的切换以及网络数据的解析,在使用上要比OkHttp便利不少。
使用方法
- 将HTTP请求转换为Java接口
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
- 生成接口实现
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
3.获得Call对象
Call<List<Repo>> repos = service.listRepos("octocat");
4.调用enqueue()方法或者execute()方法获取请求结果
源码解析
从retrofit.create()方法进入
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);//1.校验传进来接口的合法性
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {//2.动态代理service里面的方法
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 {
// 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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
到这块就要明白什么是代理模式?为什么这块要使用动态代理的设计模式?
什么是代理模式它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。对于Retrofit来说就是当调用service接口的时候,在附加一些功能。什么是动态代理就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。Retrofit就是使用了Java 语言本身提供的动态代理的语法。我们知道静态代理时编译期我们就写好的类,然后运行时通过javac生成字节码文件然后被jvm虚拟机加载。而动态代理也就是这个字节码文件不是在编译期生成而是在运行时动态生成的字节码,然后被jvm虚拟机加载。所以这个字节码文件也可以通过java命令还原成.java文件为什么使用动态代理首先,为了解耦网络请求与业务逻辑,如果不用代理模式,注解的解析就会侵入到业务层。而如果使用静态代理,一方面,我们需要在代理类中,将原始类中的所有的方法,都重新实现一遍,并且为每个方法都附加相似的代码逻辑。另一方面,如果要添加的附加功能的类有不止一个,我们需要针对每个类都创建一个代理类。所以这块使用动态代理,动态的为每一个接口方法生成代理类,所有的操作最后都有Retrofit处理,我们只需要专注业务开发。
回到代码本身通过动态代理,也就是说当调用GitHubService里面的任一方法时,都会调用InvocationHandler的invoke()方法的执行。参数method和args代表ApiService对应的方法和参数。之后调用loadServiceMethod()方法,这个是核心方法。我们来看看
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
就是传入method也就是GitHubService里面的方法参数,进行一次缓存获取,获取不到就新建ServiceMethod对象,主要方法就落在了 ServiceMethod.parseAnnotations(this, method),看看具体实现
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);//1
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.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);//2
}
第一步就是解析method方法里面的注解信息保存在RequestFactory中,里面就是校验了方法是否是REST ful API,不是就抛出异常。
第二步就是调用 HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)方法。如下
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) {//判断是不是协程的挂起函数
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
1.首先获取adapterType,这个type是我们在构建Retrofit的时候通过addCallAdapterFactory()的时候添加的,其实也就是我们service方法里面的返回值的type类型,比如是Call,Observable或者是协程类型返回值。
2.接着就是创建CallAdapter,如下
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
接着如下
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;
}
....
}
-
就是根据上面创建的
adapterType获取Retrofit创建时我们传入的adapter,有默认类型,使用Rxjava也就是它的适配器,这块就是使用了适配器模式,它将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容而不能一起工作的类可以一起工作。也就是将Call转化成了Observable。也使用了策略者模式,定义一族算法类,将每个算法分别封装起来,让它们可以互相替换。在这块就是你既可以使用默认的CallAdapter也可以使用Rxjava的适配器。也就是对应到我们service里面method的返回值。 -
接着就是创建
responseConverter,逻辑同上,也就是我们添加的GsonConverterFactory3.上面返回了CallAdapter,它是HttpServiceMethod的子类,也就是返回了HttpServiceMethod对象,接下来回到之前的调用流程也就是
@Override public @Nullable 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);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
调用HttpServiceMethod的invoke方法如下
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
创建了一个OkHttpCall对象,这块也就是对于Okhttp的封装,实际的请求还是由Okhttp执行的。我们以默认的CallAdapter为例,调用adapt方法如下
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
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);
}
};
}
这块最终就会返回ExecutorCallbackCall,然后就是我们在使用的时候调用异步请求enqueue()方法流程,交给OkHttp去执行,返回结果到
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
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(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
也就是回调到我们调用的地方,我们知道OkHttp是同步返回结果的,请求是在子线程的,Retrofit这块会切线程到主线程,这块的callbackExecutor是最终是在Retrofit初始化时
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
这块传入的,也就是
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
也就是
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
也就是通过主线程的Handler切换到线程到主线程。
最后再看看返回结果的解析吧,在OkhttpCall类里如下
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
//...
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
通过responseConverter对结果解析了解析,这个就是我们会添加的Gson解析器,然后回到结果到我们上面提到的主线程代码调用的地方。
总结
Retrofit是对于OkHttp的封装,运用多种设计模式比如建造者模式,动态代理,门面模式,适配器模式,策略者模式解耦请求与业务逻辑,功能强大,简洁易用,可扩展性好使我们可以只用专注于业务的开发。