前面讲了几篇关于网络编程基础方面的文章,我们现在来看看一些有关网络的应用框架。本篇先来分析大名鼎鼎的Retrofit2,下一篇分析OKhttp3,这些都是我们Android开发经常使用的框架,现在我们就来看看它们的内部到底是怎么实现的。
对于Retrofit2,我们还是从其使用入手,一步一步来解析。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient())
.build();
IServerAPI api = retrofit.create(IServerAPI.class);
public interface IServerAPI {
/**
* 获取购物车信息
*/
@GET("pronline/Msg?FunName@ordercart")
Call getCartData();
}
第一步,不用多说,典型的建造者模式,通过给Builder的各个成员变量赋值,然后利用这些值来构建Retrofit对象,这样我们就得到了一个Retrofit的实例,一般这个实例是单例的。
第二步,调用create方法,获得请求的接口类对象,之后我们就可以通过这个对象调用其定义的方法来进行网络请求了。如下:
Call< CartInfo > call = serverAPI. getCartData();
requestServer(call, callback)
/**
* 请求网络
* @param call 请求
* @param iResponseCallback 回调
*/
public void requestServer(Call call, final IResponseCallback iResponseCallback) {
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response != null) {
T bean = response.body();
iResponseCallback.onSuccess(bean);
}
}
@Override
public void onFailure(Call call, Throwable t) {
iResponseCallback.onFailure(t);
}
});
}
是的,使用是如此的简单,但是这种简单往往都是通过高度封装为代价的。对于我们软件开发者来言,一个框架是否好,这个框架是否简单易用占了很重要的一部分。而Retrofit一个优势,就是简洁易用,它通过注解配置网络请求的参数,采用大量的设计模式来简化我们的使用。而且它的拓展性也做的相当的好,Retrofit的功能模块高度封装,高内聚低耦合,我们可以自定义自己想要的组件,比如说我们可以自己选择解析工具等。 除此之外,Retrofit还有诸如性能好,处理速度快,代码简化等优势,给足了理由让我们去尝试使用这款网络请求框架。
现在,我们先来分析一下在初始化Retrofit实例的时候,做了哪些事:
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List converterFactories = new ArrayList<>();
private List adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
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 adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly);
}
}
Builder是Retrofit的一个静态内部类,源码如上图,这里省略了为其成员变量赋值的方法代码。可以看到先调用了Platform.get()获取当前对应的平台,这里我们主要看一下Android的平台代码:
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
Android平台复写了defaultCallbackExecutor方法,提供的执行器将任务放到主线程去执行的;另外也复写了defaultCallAdapterFactory方法,返回一个ExecutorCallAdapterFactory对象。回到Builder构造函数里,接着在converterFactories集合中添加了一个默认的内置转换器,它主要是用来对HTTP和对象之间的数据转换,比如我们前面在初始化Builder的时候调用了addConverterFactory(GsonConverterFactory.create()),目的是通Gson的方式来转换数据。
再来看Builder中的build方法,通过给baseUrl、callFactory、callbackExecutor、adapterFactories和converterFactories这几个成员变量赋值来构建Retrofit实例。
接下来,我们再来看看最重要的一个方法,就是这个create:
public T create(final Class 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);
}
});
}
该方法中,首先 Utils.validateServiceInterface(service),检查我们定义的接口类文件是否合法;然后通过validateEagerly判断是否需要将接口里面的方法一次性的先加载到内存中,如果不加,后面则通过单个调用来将其加入到内存,如果我们定义的接口方法多,并且有些接口不是经常用的话,可以不先加载,这样节约内存;接下来,就是一个动态代理的过程了,对我们定义的每一个接口方法进行拦截,在invoke方法中,首先判断如果调用的方法是在Object.class中声明的,则正常调用,我们在使用中,都是在自己的接口文件中声明的这些方法,所以,这个一般不走;接下来判断platform.isDefaultMethod(method),在Android平台中这个始终未false,所以也不走;看最后3行代码,首先loadServiceMethod(method),就是刚才说的将该方法加载进内存,来看一下这个方法源码:
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对象中,然后将此对象和方法保存到一个LinkedHashMap类型的serviceMethodCache变量中,这样以后调用同样的方法时,直接从缓存中去,节省时间。现在我们来看看ServiceMethod具体的封装过程:
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
//主要代码
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
同样采取的是建造者模式,创建callAdapter、responseConverter,获取responseType,解析方法注解,解析参数。这里重点分析一下callAdapter,因为后面要用,来看看其具体过程:
private CallAdapter> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
可以看到调用的是retrofit.callAdapter(returnType, annotations),跟过去:
public CallAdapter> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
.append(returnType)
.append(".\n");
if (skipPast != null) {
builder.append(" Skipped:");
for (int i = 0; i < start; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
builder.append('\n');
}
builder.append(" Tried:");
for (int i = start, count = adapterFactories.size(); i < count; i++) {
builder.append("\n * ").append(adapterFactories.get(i).getClass().getName());
}
throw new IllegalArgumentException(builder.toString());
}
大致的意思就是遍历retrofit中的集合adapterFactories中的对象,通过returnType和注解调用get方法,找到对应的adapter,然后返回,adapterFactories我们在之前初始化retrofit的时候执行的是这句代码:
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
这里的platform是Android平台,在最初我们已经讲了Android平台覆写了defaultCallAdapterFactory方法,如下:
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
所以Retrofit的callAdapter方法返回的adapter是ExecutorCallAdapterFactory对象中的get方法的返回值。也就是说serviceMethod.callAdapter指向的是ExecutorCallAdapterFactory对象中的get方法的返回值。
回到Retrofit的create方法中,接下来调用了OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args),将该方法和具体的参数值封装进一个OkHttpCall对象中;最后调用了serviceMethod.callAdapter.adapt(okHttpCall),由上面的分析得出,这里的serviceMethod.callAdapter就是ExecutorCallAdapterFactory对象的get方法返回值,看其源码:
@Override
public CallAdapter> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
返回了CallAdapter的一个匿名对象,其adapt方法中返回的是ExecutorCallbackCall子对象,并且将callbackExecutor 和 call(前面的okHttpCall)封装了进去,再来看看ExecutorCallbackCall这个静态内部类:
static final class ExecutorCallbackCall implements Call {
final Executor callbackExecutor;
final Call delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override
public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback() {
@Override
public void onResponse(Call call, final Response 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 call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
@Override
public boolean isExecuted() {
return delegate.isExecuted();
}
@Override
public Response execute() throws IOException {
return delegate.execute();
}
@Override
public void cancel() {
delegate.cancel();
}
@Override
public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override
public Call clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override
public Request request() {
return delegate.request();
}
}
可以看到这个类里面的方法都是采用委托的方式,交给delegate去执行,这个delegate就是前面我们传入的OKHttpCall对象。
至此,Retrofit的create方法就分析完成,总结一下这个方法的过程:
1. 检查接口文件是否合法
2.判断是否需要预加载所有方法
3.动态代理拦截每个方法,在这里面由分为3个步骤:
3.1 初始化ServiceMethod,并和方法关联,缓存到内存中
3.2 将ServiceMethod和实际的参数值封装进OkHttpCall对象中
3.3 调用serviceMethod中callAdapter对象的adapt方法,获得ExecutorCallbackCall对象,并将OkHttpCall封装进去,返回此ExecutorCallbackCall对象。
现在,我们拿到了这个ExecutorCallbackCall对象后,就开始请求网络,同步调用其execute()方法,异步调用其enqueue(Callback
@Override public void enqueue(final Callback callback) {
if (callback == null) throw new NullPointerException("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) {
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)
throws IOException {
Response response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
总的来说,就是先调用createRawCall方法创建okhttp3.Call对象,然后通过此对象去请求网络,完成之后回调处理方法。那么我们看一下createRawCall的源码:
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;
}
首先调用ServiceMethod的toRequest方法,并将实际参数值传递进去,来构造一个HTTP请求对象;然后将此请求传递到serviceMethod.callFactory的newCall方法中,来构造一个okhttp3.Call ,这里的serviceMethod.callFactory是什么?我们看到在serviceMethod的构造方法中有这样一句代码:
ServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
...
}
可以看出这里的callFactory就是Retrofit的callFactory方法的返回值,而在当初初始化Retrofit的时候是这样的:
public Retrofit build() {
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
...
}
public Builder client(OkHttpClient client) {
return callFactory(checkNotNull(client, "client == null"));
}
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = checkNotNull(factory, "factory == null");
return this;
}
所以,这里的callFactory指向的就是一个OkHttpClient对象,因此createRawCall()方法返回的okhttp3.Call就是OkHttpClient中newCall方法的返回值。进入这个方法:
@Override
public Call newCall(Request request) {
return new RealCall(this, request);
}
可以看到直接将请求封装进RealCall对象中返回,由此可以知道最后实际发起请求的就是RealCall这个对象。由于RealCall和OkHttpClient都是okhttp3框架里面的东西,这里放到下一篇去讲解。
最后总结一下,本篇讲了retrofit的具体请求过程,大致分为三步:
1.初始化retrofit,并根据实际需求配置retrofit
2.解析我们定义的接口文件及其方法信息
3.通过实际参数值构造HTTP请求对象,并交给RealCall去真正的执行请求。
本篇只是讲解一下请求过程,还有其它一些东西没有讲到,比如retrofit中的converterFactories转换器的具体转换过程,以及构造HTTP请求的具体过程,待以后有时间再行分析。