1、前言
- 在
Android
中,网络请求操作十分常见; - 在众多的网络请求框架中,以
Retrofit
最为好用; - 本篇文章对
Retrofit2.0
进行一个源码的解析,以此来深入研究其实现原理;
2、分析步骤
- 创建
Retrofit
对象; - 创建网络接口对象;
- 请求网络;
假如你对
Retrofit
的使用步骤还不清楚,可以看看这篇文章:Android:Retrofit的使用步骤
3、源码解析
3.1、创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()//步骤1、通过建造者模式创建Retrofit对象
.baseUrl(Constant.service)//步骤2、添加网络请求地址
.addConverterFactory(GsonConverterFactory.create()) // 步骤3、添加Gson转换器
.build();//步骤4、最终创建Retrofit对象
观察以上代码可以知道,创建Retrofit
对象是通过设计模式中的建造者模式实现的,下面通过主要的4个步骤,逐步的解开创建Retrofit
对象的面纱;
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- 步骤1、
new Retrofit.Builder()
:
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;//网络请求工厂
private HttpUrl baseUrl;//网络请求地址
private List<Converter.Factory> converterFactories = new ArrayList<>();//数据转换器工厂集合
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//网络请求适配器集合
private Executor callbackExecutor;//回调执行器
private boolean validateEagerly;
public Builder() {
this(Platform.get());//获取平台对象,提供Android、IOS、Java平台
}
Builder(Platform platform) {
this.platform = platform;
// 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());//设置默认的数据转换器到集合中
}
在Retrofit
的内部类Builder
中,设置了一些全局变量,callFactory
是网络请求对象工厂、baseUrl
是网络请求地址、converterFactories
是数据转换器工厂集合、adapterFactories
是网络请求适配器集合、callbackExecutor
是回调执行器;可以看到使用了大量的XXXFactory
,即工厂模式;
工厂模式:定义一个创建对象的接口,由子类去决定实例化哪一个类,将实例化对象的操作延迟到子类
在构造函数中,设置了兼容的平台,默认是Android
,另外还提供了IOS
、Java
,这里我只看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());//使用Handler切换线程
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
在Android
平台中,设置了默认的回调执行器:MainThreadExecutor
,其作用就是切换线程操作,可以看到就是使用了Handler
;设置默认的网络请求适配器工厂:ExecutorCallAdapterFactory
,另外还提供了其他网络请求适配器,比如我们熟知的:RxJavaCallAdapterFactory
;现在我们只看ExecutorCallAdapterFactory
的实现:
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {//把默认的回调执行器传进来
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {//实例化网络请求适配器对象,后面会用到
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {//把call、回调执行器传到ExecutorCallbackCall类中,该类是一个装饰类,真正的网络请求操作是在okHttpCall进行
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {//网络请求适配器的内部类,网络请求操作是在ExecutorCallbackCall进行
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("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);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> 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<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
}
ExecutorCallAdapterFactory
继承自CallAdapter.Factory
,把默认回调执行器传进来,这样就可以对网络请求操作进行相应的回调,在这里可以看到内部类的ExecutorCallbackCall
,该类的作用是对OkHttpCall
进行封装,真正执行网络请求操作是OkHttpCall
对象;
装饰者模式:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。
- 步骤2、
Builder.baseUrl(Constant.service)
:
public Builder baseUrl(String baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
HttpUrl httpUrl = HttpUrl.parse(baseUrl);//把网络请求地址转换层HttpUrl类型
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
checkNotNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
在这个地方,主要把网络请求地址转换成HttpUrl
类型,其他没什么,直接过;
- 步骤3、
Builder.addConverterFactory(GsonConverterFactory.create())
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
这个是不是更简单,传入GsonConverterFactory
对象,用Gson
来处理返回的数据,并且放到converterFactories
集合中,记不记得之前也存了一个默认的数据解析器,那么现在集合中有2个了,不过不用管,后面会用到;如果想要用其他解析方式,也可以自定义解析器来实现,现在我们只看GsonConverterFactory
:
public final class GsonConverterFactory extends Converter.Factory {
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create() {
return create(new Gson());//创建Gson实例
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
可以看到GsonConverterFactory
继承自Converter.Factory
,然后内部实例化了Gson
对象,那么就通过Gson
对象的方法对数据进行解析了;
- 步骤4、
Builder.build()
:
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> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));//设置默认的网络请求适配器
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);//真正创建Retrofit对象
}
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
在该方法中,是真正创建Retrofit
对象,在内部对之前赋值的对象进行一个初始化,设置默认的网络请求工厂:OkhttpClient
,其是OkHttp
的一个封装类,所以Retrofit
默认用OkHttp
请求网络;还有设置默认的回调执行器、网络请求适配器、数据解析器都在上面已经提到了,这里只是进行一个初始化操作;
对于创建Retrofit
对象的总结:
- 设置网络请求地址:
baseUrl
; - 设置默认的网络请求工厂:
OkHttpClient
; - 设置默认网络请求适配器工厂:
ExecutorCallAdapterFactory
; - 设置默认的回调执行器:
MainThreadExecutor
; - 设置默认的数据解析器:
BuiltInConverters
,另外手动添加了GsonConverterFactory
解析器; - 创建了
Retrofit
对象,为创建网络请求对象作出铺垫;
3.2、创建网络接口对象
service = retrofit.create(MyApiService.class);
public interface MyApiService {
@GET("doctor/v2/group/list")
Call<Bean> getCall();
}
既然已经创建了Retrofit
对象,那么就可以创建网络接口实例了,把MyApiService
接口传入到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, Object... args)//每次调用MyApiService里的方法时都会回调该方法
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);//步骤1、通过Method获取ServiceMethod
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);//把ServiceMethod把传入到OkHttpCall
return serviceMethod.callAdapter.adapt(okHttpCall);//步骤2、把okHttpCall传入网络请求适配器中
}
});
}
从以上代码可知道,创建网络接口对象是通过动态代理模式来实现的;
代理模式:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
动态代理:动态代理类的源码是在程序运行期间根据反射等机制动态的生成
每次调用接口类中的方法时,都会回调到invoke
方法中,所以直接看invoke
方法就行,我们还是通过步骤的形式来做分析;
- 步骤1、
ServiceMethod serviceMethod = loadServiceMethod(method)
这句话通过传入接口类的方法加载了一个ServiceMethod
对象,该对象可以说保存了所有请求网路的东西,后面可以看到;
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
进行了一个缓存,serviceMethodCache
是一个LeakHashMap
类型的数据集合,对于这个很熟悉了,也就是最近最少使用的缓存机制,这样每次调用的时候就不用重新创建了;对于ServiceMethod
对象也是通过建造者模式来实现的;
static final class Builder<T> {
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations;
final Annotation[][] parameterAnnotationsArray;
final Type[] parameterTypes;
Type responseType;
boolean gotField;
boolean gotPart;
boolean gotBody;
boolean gotPath;
boolean gotQuery;
boolean gotUrl;
String httpMethod;
boolean hasBody;
boolean isFormEncoded;
boolean isMultipart;
String relativeUrl;
Headers headers;
MediaType contentType;
Set<String> relativeUrlParamNames;
ParameterHandler<?>[] parameterHandlers;
Converter<ResponseBody, T> responseConverter;
CallAdapter<?> callAdapter;
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
可以看到在ServiceMethod
的Builder
类中,具有大量的信息,比如Retrofit
对象、请求体、请求头、参数等等,也就是说要进一个网络请求的东西都包含了;并且在构造函数中通过方法上的注解、参数进行一个处理;
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);
}
···
}
···
return new ServiceMethod<>(this);
}
从以上代码可以看到,首先是调用createCallAdapter
方法配置网络请求适配器:
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);
}
}
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
···
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;
}
}
····
}
可以看到,根据方法的返回类型和注解从网络请求适配器集合中遍历获取相应的网络请求适配器,默认的就是ExecutorCallAdapterFactory
;然后回到Build
方法中,下一个就是配置数据解析器:
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
Type type, Annotation[] annotations) {
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;
}
}
对于配置数据解析器的方式,和配置网络请求适配器的方式有异曲同工之处;通过响应类型和注解通过遍历数据解析器集合的方式创建数据解析器;
回到Build
方法中,可以看到下一个操作是遍历注解,然后调用parseMethodAnnotation
方法:
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.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
该方法中对注解内容对照请求方法,GET
、POST
、PUT
、HEAD
等等之类的;
在Build
方法中,最终实例化了ServiceMethod
对象;
- 步骤2:、
serviceMethod.callAdapter.adapt(okHttpCall);
在该步骤之前先实例化了okHttpCall
,它是OkHttp
的一个封装类;
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
然后把okHttpCall
传入到网络请求适配器中的adapt
里,也就是ExecutorCallAdapterFactory
对象,直接看该adapt
方法:
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);//创建了ExecutorCallbackCall对象
}
};
}
在adapt
方法中,实例化了ExecutorCallbackCall
对象,刚开始的时候就说过了,它是一个装饰类,真正执行网络请求操作还是OkHttpCall对象,这样在invoke
方法返回中就获得了ExecutorCallbackCall
对象。到此,网络请求对象成功创建,这样就可以进行真正的网络请求操作啦;
创建网络请求对象总结:
- 通过动态代理的方式处理请求接口类;
- 通过返回类型和注解从网络请求适配器集合中创建网路请求适配器
- 通过请求类型和注解从数据解析器集合中创建数据解析器;
- 解析方法中的注解;
- 从网络请求适配中配置真正的网络请求操作类
ExecutorCallbackCall
;
3、请求网络
Call<Bean> call = service.getCall();
call.enqueue(new Callback<Bean>() {
@Override
public void onResponse(Call<Bean> call, Response<Bean> response) {
}
@Override
public void onFailure(Call<Bean> call, Throwable t) {
}
});
从上面的分析中,已经知道ExecutorCallbackCall
是实现网络请求操作的类,所以直接看该类的enqueue
的方法:
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {//使用默认回调执行器即:MainThreadExecutor
@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);
}
});
}
});
}
从上面的异步请求操作中可以看出,delegate
实际是OkHttpCall
类,这里可以看作是静态代理模式;并且使用默认回调执行器即:MainThreadExecutor
来回调数据,这个是最初在创建Retrofit
时配置的,这样就完成了一次Retrofit
请求框架的请求操作;
4、总结
-
Retrofit
实质上是对OkHttp
的封装框架; - 通过注解配置网络参数,内部封装
OkHttp
来执行网络操作; - 通过动态代理的方式动态地创建网络请求对象,并且加入缓存机制更加节省消耗,
- 通过集合的方式设置其他的网络请求适配器和数据解析器,灵活性、扩展性更高;