一、Retrofit2源码地址
Retrofit2源码地址:https://github.com/square/retrofit
二、Retrofit2简单使用
1、首先创建用于网络请求的API接口:
public interface NetService {
@GET("cozing")
Call<NetResponse> serviceApi();
}
2、创建用于接收请求返回的数据接收:
public class NetResponse {
private int id;
private String name;
}
3、创建Retrofit实例并做交易请求:
public class Retrofit2TestForBlogActivity extends BaseActivity{
...
private void retrofitTest(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://github.com/") //必须以"/"结尾,不然将抛出异常
.addConverterFactory(GsonConverterFactory.create())
//.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
NetService netApi = retrofit.create(NetService.class);
Call<NetResponse> call = netApi.serviceApi();
try {
//① 同步请求
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
//②异步请求
call.enqueue(new Callback<NetResponse>() {
@Override
public void onResponse(Call<NetResponse> call, Response<NetResponse> response) {
}
@Override
public void onFailure(Call<NetResponse> call, Throwable t) {
}
});
}
}
通过以上代码,咱们完成了请求,其中咱们向:
url = https://github.com/cozing
发送GET请求,在注释①处发起同步请求,在注释②处发送异步请求,交易的结果通过调用返回的Response对象实例的response.body()获取,这个结果就是咱们在构建网络请求时传入的NetResponse数据结构。
接下来看Retrofit2整体架构流程图。
三、架构流程
1、流程图
2、流程讲解
1、创建Retrofit实例;
2、创建网络请求接口和相关属性注解;
3、通过动态代理解析请求接口的注解,并生成网络请求对象;
4、通过CallAdapter进行平台适配,平台包括(Android/java8/iOS);
5、通过OkHttpCall发送网络请求;
6、通过Converter数据转换适配器转换交易返回的数据;
7、通过线程切换执行器切换到主线程(仅限异步请求)。
四、源码分析
1、Retrofit的内部成员变量
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>(); //网络请求缓存,如:请求方法、请求头、请求体,各种适配器等
final okhttp3.Call.Factory callFactory; //okhttp工厂,真正发送交易的处理类
final HttpUrl baseUrl; //请求url前半部,基地址
final List<Converter.Factory> converterFactories; //数据转换器工厂集
final List<CallAdapter.Factory> adapterFactories; //网络请求适配器工厂集
final @Nullable Executor callbackExecutor; //异步请求结果线程切换执行器
final boolean validateEagerly; //标志位、是否马上解析接口方法
...
}
2、Retrofit内部类Builder
public final class Retrofit {
...
public static final class Builder {
private final Platform platform; //适配平台,通常默认android
private @Nullable okhttp3.Call.Factory callFactory; //okhttp网络请求工厂,默认okhttp
private HttpUrl baseUrl; //基地址
private final List<Converter.Factory> converterFactories = new ArrayList<>(); //数据转换器集,用于生产数据转换器,默认GsonConverterFactory
private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); //网络请求适配器,如RxJava2CallAdapterFactory
private @Nullable Executor callbackExecutor; //执行异步回调的线程切换
private boolean validateEagerly; //是否立即解析接口注解方法
}
...
}
3、创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://github.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
内部类Builder实现:
public final class Retrofit {
...
public static final class Builder {
...
Builder(Platform platform) {
this.platform = platform;
converterFactories.add(new BuiltInConverters());//添加默认数据解析器
}
public Builder() {
this(Platform.get());
}
}
}
咱们在创建Builder实例时调用的是Builder的无参构造放法,里面调用了Builder(Platform)这个构造方法,传入的是Platform.get()返回数据,这个方法是获取适配平台,默认是Android,其他平台咱们不做过多分析,直接查看Android:
class Platform {
...
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
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);
}
}
}
...
}
可以看到在创建Builder实例的设配平台时,将工作线程切换到了主线程,这也是后面可以通过主线程回调返回请求数据的原因。
接着将会在Builder的有参构造方法中的添加Retrofit默认的数据解析器:
converterFactories.add(new BuiltInConverters());
4、Builder.build()方法
public final class Retrofit {
...
public static final class Builder {
...
public Retrofit build() {
if (baseUrl == null) { //对baseurl进行非空判断
throw new IllegalStateException("Base URL required.");
}
//注释①
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient(); //创建okhttp客户端
}
//注释②
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
}
首先咱们看注释①处,上面说过Retrofit2框架的底层发送交易其实是提交给了okhttp框架,在okhttp3源码讲解时咱们说过在okhttp中OkhttpClient在整个进程中只创建一次,所以在这里做了相关判断。
注释②处,可以看到是获取回调执行器,如果没有设置回调执行器,就创建一个默认的主线程回调执行器。
最后调用Retrofit的构造方法,创建一个Retrofit实例。可以看到整个创建Retrofit过程中,通过构建者模式来执行一系列初始化和对象的创建。
5、retrofit.create()
接着咱们创建了网络请求接口类NetService.class,在下面的步骤中咱们调用retrofit.create(NetService.class),这个方法是Retrofit的核心,内部采用动态代理,将咱们自定义的网络请求接口转换成一个ServiceMethod对象,ServiceMethod就是咱们Retrofit中的具体请求对象,里面封装了网络请求所必须的全部信息,包括请求方法、url、请求头、请求体等网络配置参数!
咱们现在看看create()源码:
...
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) { //创建retrofit实例时提到的标志位
//注释①
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 (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.callAdapter.adapt(okHttpCall);
}
});
}
...
咱们先看注释①处,如果提前验证的标志位为true,将会调用eagerlyValidateMethods(service)方法,咱们来看:
...
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
...
可以看到这个方法内部通过反射机制,来获取咱们自定义的请求接口对象类的内部方法。isDefaultMethod默认为false,因此loadServiceMethod(method)方法一定会走到,咱们接着看这个方法:
...
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是一个ConcurrentHashMap实例,ConcurrentHashMap是HashMap的一个线程安全的、支持高效并发的版本。继续看代码,创建serviceMethod时并不是每次都创建一个新的实例,而是先去缓存吃中去获取,如果缓存池中没有存储,则会调用builder构建者模式去重新创建method,并将该对象实例存入serviceMethodCache缓存池中。
接着看注释②,返回了一个动态代理对象,如果不清楚什么是动态代理,请点击这里。熟悉动态代理模式的童鞋应该都知道
真正处理事务逻辑的地方是在代理对象的invoke回调方法内,在Retrofit2代码里,也就是注释③处。
看注释③的invoke方法,对Retrofit源码理解的重中之重,就是这个方法中的最后三行。接下来咱们将在6、7、8点详细分析这三行代码。
6、loadServiceMethod()
这个方法用于加载serviceMethod,一个serviceMethod对应咱们定义的网络请求接口中的一个方法,比如栗子中的serviceApi()这个方法。接着来看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 = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
...
先看ServiceMethod的成员变量:
final class ServiceMethod<R, T> {
...
private final okhttp3.Call.Factory callFactory; //okhttp call的工厂
private final CallAdapter<R, T> callAdapter; //网络请求适配器
private final HttpUrl baseUrl; //基地址
private final Converter<ResponseBody, R> responseConverter; //数据转换器
private final String httpMethod; //网络请求方法
private final String relativeUrl; //网络请求相对地址,和基地址拼接成完整地址
private final Headers headers; //请求头
private final MediaType contentType; //请求体
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers; //方法参数处理器
...
}
咱们开始时候说过,Retrofit2底层是基于okhttp框架来发送请求,可以看到在ServiceMrthod中维护了okhttp用于网络请求的Call工厂,用于生产Call,并且ServiceMrthod声明了网络请求所需元素的所有基本信息。咱们看ServiceMrthod的源码发现,它和Retrofit这个类的初始化非常相似,都是通过构建者模式来创建实例。咱们回过头看loadServiceMethod()方法的:
...
result = new ServiceMethod.Builder<>(this, method).build();
...
这一行,跟进去Builder内部类:
final class ServiceMethod<R, T> {
...
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit; //retrofit实例
this.method = method; //网络请求方法
this.methodAnnotations = method.getAnnotations(); //网络请求方法的注解
this.parameterTypes = method.getGenericParameterTypes(); //获取网络请求方法里的注解的类型
this.parameterAnnotationsArray = method.getParameterAnnotations(); //获取网络请求方法里的注解的内容
}
...
}
然后调用ServiceMrthod
...
static final class Builder<T, R> {
...
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);
}
...
//注释④
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);
}
...
return new ServiceMethod<>(this);
}
...
...
看注释①的createCallAdapter,创建callAdapter,内部实现:
...
private CallAdapter<T, R> 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 (CallAdapter<T, R>) 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中获取网络请求接口适配器。首先从网络请求接口方法中获取注释,然后根据注释和注释返回类型,接着调用retrofit.callAdapter()方法从retrofit中获取适配器。咱们跟着代码会发发现其实最后调用的是retrofit的nextCallAdapter(),来看看它内部实现的主要代码:
...
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
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;
}
}
...
}
...
在for循环中,根据请求参数在网络适配工厂中创建网络适配器并返回该适配器,
接着看build()方法中的注释②:
responseConverter = createResponseConverter();
跟进去:
...
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);
}
}
...
这个方法是创建网络请求返回数据转换器,和创建网络请求适配器的方式一样,调用的是retrofit的responseBodyConverter()方法,内部真正调用的是nextResponseBodyConverter()方法,nextResponseBodyConverter()的内部主要实现:
...
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
...
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) {
return (Converter<ResponseBody, T>) converter;
}
}
...
}
...
可以看到,和创建网络请求适配器一样的创建方法,根据响应类型和请求方法注释数值,从数据转换器工厂中创建数据转换器并返回。
继续看build()方法中的注释③:
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
是解析请求接口中的所有注释。
接着看注释④的代码:
...
public ServiceMethod build() {
...
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);
}
...
}
....
这部分做的主要是解析网络请求接口的参数,包括自定义请求接口参数和配置的请求参数,其中ParameterHandler类就是接口参数解析器。
至此,loadServiceMethod()方法的分析完成,这个方法主要是创建并加载ServiceMehod,用于解析网络请求接口参数、网络请求适配器、response数据解析器等工作。
7、创建OkHttpCall对象
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
咱们前面说过Retrofit2框架的交易发送是由okhttp实现, 所以很容易想到,这个OkHttpCall就是对okhttp的call对象的封装,咱们现在看OkHttpCall的实现:
final class OkHttpCall<T> implements Call<T> {
...
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
...
@Override public void enqueue(final Callback<T> callback) {
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();
}
}
});
...
@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());
}
...
}
代码有点多,但是逻辑还是很清晰的,内部维护了一个okhttp3.Call rawCall的对象,接着看下面两个方法:enqueue()和execute(),可以看到内部调用的是rawCall的对应方法,也就是调用okhttp3.Call的enqueue()和execute()。
8、serviceMethod.adapt(okHttpCall)
这个方法很显然使用适配器模式,将某些咱们需要处理的事件,适配成其他平台可以使用的类型,并在该平台使用。这里调用serviceMethod的adapt适配方法,传入了上面步骤7中创建的OkHttpCall实例,并将适配对象返回。adapt()方法源码:
final class ServiceMethod<R, T> {
...
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
...
}
可以看到内部调用的是callAdapter.adapter(call),而callAdapter对象实例是在loadServiceMethod()方法中调用ServiceMethod构建者模式创建实例时候创建的:
final class ServiceMethod<R, T> {
...
static final class Builder<T, R> {
...
CallAdapter<T, R> callAdapter;
public ServiceMethod build() {
...
callAdapter = createCallAdapter();
...
}
}
...
}
在调用callAdapter的adapter()方法,其实就是把一个个Retrofit中的Call适配成其他平台也能使用的Call类型,比如咱们栗子中使用的是RxJava2CallAdapterFactory.create()来创建了一个RxJava2CallAdapter的适配器来适配RxJava2平台,适配成RxJava2平台能使用的Call。
咱们接下来看Retrofit的CallAdapter接口中的Rxjava2CallAdapter实现类的adapter()方法:
final class RxJava2CallAdapter implements CallAdapter<Object> {
...
@Override public <R> Object adapt(Call<R> call) {
Observable<Response<R>> responseObservable = new CallObservable<>(call);
Observable<?> observable;
...
return observable;
}
...
}
可以看到,该适配方法返回了一个Observable被观察者对象。所以在咱们栗子中最后创建Retrofit的Call接口的实例对象时,也就创建了一个被观察者对象。
最后,通过Retrofit的Call实现类,调用execute()方法,也就是调用okhttp3.Call的execute()方法来发送同步请求,请求结果同步返回;调用enqueue()方法,也就是调用okhttp3.Call的enqueue()方法来发送异步请求,请求结果通过Callback接口对象回调返回。
至此,有关Retrofit2的源码分析结束。
六、总结
咱们通过观察Retrofit2的源码发现Retrofit2代码量其实不多,但是有些童鞋看完整篇文章可能还一脸懵逼,这TM也太复杂了!其实不然,因为Retrofit2内部采用了大量的设计模式,导致咱们分析源码时候需要经常跳转着看源码,所以建议咱们在分析Retrofit2源码时候,一定要跟着流程仔细阅读源码,如果读懂了Retrofit2的流程,就会发现其实Retrofit2的整体框架还是挺简单的。