一、简介
retrofit是square开发的一个网络加载库,主要用于Android和Java。Retrofit对OKHttp进行了封装,加入了各种设计模式,注解,反射,使用起来更加方便。
二、使用方法
retrofit的使用大致分为三个部分:定义网络接口、创建retrofit对象、创建网络接口的动态代理、调用网络接口
2.1 定义网络接口
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
上面的例子中创建了一个GitHubService接口,接口中定义了一个listRepos方法,listRepos一个String类型参数user,返回值是Call>。
同时,listRepos中有很多注解,我们一一分析这些注解:
@GET("users/{user}/repos")表明该方法是一个GET请求,("users/{user}/repos")是网络请求的相对路径,启动{user}是可变部分。
@Path("user")是一个参数注解,表明该参数是用来替换网络请求路径中的{user},总而组成动态变化的路径。
2.2 创建retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create()) //结构化数据和java对象之间的转化
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //适配不同平台(JAVA8、Android、RxJava,Guava)
.build();
可以看出这是一个builder模式,用于构建retrofit对象。上面的例子中:
1.设置了baseUrl,用于和接口中的相对地址一起组成完成的网络请求地址;
2.设置了ConverterFactory,用于将OKHttp的call转化为不同平台的call(因为retrofit底层是OKHttp,retrofit的网络请求都是通过调用OKHttp来进行的。同时retrofit还支持在不同平台上使用,因此就需要将OKHttp原生的call换转为不同平台的call,这就是适配器模式);
3.设置了数据转换器,用于将服务器返回的json\xml\protobuf等格式的数据转化为java对象。
2.3 创建网络加载接口的动态代理
GitHubService service = retrofit.create(GitHubService.class);
retrofit.create创建了一个接口的动态代理,每次调用接口的方法,都会执行动态代理的invoke方法,用于执行真正的网络加载逻辑。
2.4 调用网络加载接口
Call> repos = service.listRepos("octocat");
repos.enqueue(new Callback>() {
@Override
public void onResponse(Call> call, Response> response) {
}
@Override
public void onFailure(Call> call, Throwable t) {
}
});
调用接口,返回一个retrofit的call对象,该对象保存网络请求的参数,提供同步、异步加载,内部调用OKHttp的call执行网络通信。
三、retrofit源码概述
retrofit内部使用了很多设计模式(builder模式、适配器模式、工厂模式、装饰模式等),提供了很多注解,使用了动态代理。
3.1 框架流程图
3.2 初始化和准备
3.2.1retrofit的成员对象
代码位置retrofit2.Retrofit
private final Map> serviceMethodCache = new ConcurrentHashMap<>(); //缓存method和其解析对象
final okhttp3.Call.Factory callFactory; //okHttp工厂
final HttpUrl baseUrl;
final List converterFactories; //数据转换器集合
final List callAdapterFactories; //网络适配器工厂集合
final @Nullable Executor callbackExecutor; //异步请求结果线程切换器
final boolean validateEagerly; //是否提前解析所有method并缓存
retrofit存储着网络请求的基本信息。
3.2.2 retrofit的静态内部类builder与建造者模式
代码位置retrofit2.Retrofit
public static final class Builder {
private final Platform platform; //
private @Nullable okhttp3.Call.Factory callFactory;
private @Nullable HttpUrl baseUrl;
private final List converterFactories = new ArrayList<>();
private final List callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
Builder(Platform platform) {
this.platform = platform;
}
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {}
/**
* 设置网络请求客户端
*/
public Builder client(OkHttpClient client) {}
/**
* 设置底层网络请求的工厂方法,retrofit底层是OkHttp
*/
public Builder callFactory(okhttp3.Call.Factory factory) {}
/**
* 设置基础的url,比如https://www.jianshu.com/u/9a2d2f05977c 的基础url是https://www.jianshu.com/
*/
public Builder baseUrl(URL baseUrl) {}
/**
*
*/
public Builder baseUrl(String baseUrl) {}
/**
*
*/
public Builder baseUrl(HttpUrl baseUrl) {}
/**
* 设置数据转换器的工厂
*/
public Builder addConverterFactory(Converter.Factory factory) {}
/**
* 设置网络适配器工厂
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {}
/**
* 设置回调函数执行器
*/
public Builder callbackExecutor(Executor executor) {}
/** Returns a modifiable list of call adapter factories. */
public List callAdapterFactories() {}
/** Returns a modifiable list of converter factories. */
public List converterFactories() {}
/**
* 创建retrofit对象
*/
public Retrofit build() {}
}
retrofit有一个静态内部类builder,他用于延迟创建retrofit对象。这是一个典型的建造者模式。builder内部的成员变量和retrofit一样,还提供了很多初始化成员变量的方法,这些方法都返回builder对象本身,用于链式编程。
3.2.2 创建网络请求接口的动态代理
代码位置retrofit2.Retrofit
/**
* 返回网络请求接口的动态代理
*/
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
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();
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); //解析接口,返回动态代理
}
});
}
上面的代码使用Proxy.newProxyInstance为接口生成动态代理,每次调用接口,真正执行逻辑的是代理。
3.3 调用网络请求接口
3.3.1 动态代理中的逻辑
代码位置retrofit2.Retrofit
/**
* 创建动态代理
*/
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();
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); //解析接口,返回动态代理
}
});
}
/**
* 提前解析
*/
private void eagerlyValidateMethods(Class> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) { //遍历所有method
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method); //从缓存中获取该method对应的methodService(key是method),如果缓存中没有,解析该方法的所有注解,生成serviceMethod,添加缓存
}
}
}
/**
* 解析的实际处理方法,首先从缓存中获取,缓存中没有再进行解析(调用ServiceMethod.parseAnnotations),并把缓存结果lru缓存
*/
ServiceMethod> loadServiceMethod(Method method) { //从缓存中获得ServiceMethod
ServiceMethod> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method); //先从hua
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result); //解析出来srviceMethod,放入缓存中
}
}
return result;
}
我们每次调用网络请求接口,都会调用InvocationHandler的invoke方法。invoke方法中调用loadServiceMethod(method)方法解析接口。
loadServiceMethod(method)方法中首先检查缓存,如果该method没有对应的ServiceMethod缓存,则调用ServiceMethod.parseAnnotations解析接口信息,并缓存起来。
代码位置retrofit2.ServiceMethod
abstract class ServiceMethod {
static ServiceMethod parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //调用RequestFactory解析该方法中的注解和参数注解
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); //传入参数和注解,生成HttpServiceMethod对象
}
abstract @Nullable T invoke(Object[] args);
}
ServiceMethod是一个抽象类,内部有两个方法。static
HttpServiceMethod继承了ServiceMethod,实现了invoke方法。
代码位置retrofit2.HttpServiceMethod
@Override final @Nullable ReturnT invoke(Object[] args) { //反射方法,将原来的方法转换成httpCall
Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); //先生成okhttpcall
return adapt(call, args); //然后使用callAdapter生成对应平台的call
}
invoke方法中先创建了一个OkHttpCall对象,然后使用CallAdapter创建了对象平台的call。
总结:首先从缓存中获取method对应的serviceMethod,如果没有,调用ServiceMethod解析接口,并缓存;然后使用解析到的接口数据,接口参数,指定的工厂方法创建OKHttpCall;最后调用CallAdapter创建对应平台的call。
3.3.2 执行网络请求
从3.3.1小节中我们得知,每次调用接口,执行逻辑的都是代理(代理中解析接口注解,创建OkHttpCall,最后使用CallAdapter创建指定平台的call)。
假设我们设置的CallAdapterFactory是RxJava2CallAdapterFactory,我们看一下RxJava2CallAdapter中的逻辑。
代码位置retrofit2.adapter.rxjava2.RxJava2CallAdapter
@Override public Object adapt(Call call) {
Observable> responseObservable = isAsync //创建RxJava的Observable,对OKHttp的call进行包装
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
if (isFlowable) {
return observable.toFlowable(BackpressureStrategy.LATEST);
}
if (isSingle) {
return observable.singleOrError();
}
if (isMaybe) {
return observable.singleElement();
}
if (isCompletable) {
return observable.ignoreElements();
}
return RxJavaPlugins.onAssembly(observable);
}
RxJava2CallAdapter中的adapter方法创建了一个被观察者,该被观察者对OkHttp的call进行了包装,从而使得retrofit可以支持RxJava。
我们继续看responseObservable。
代码位置retrofit2.adapter.rxjava2.CallEnqueueOnSubscribe
final class CallEnqueueOnSubscribe implements OnSubscribe> {
private final Call originalCall;
CallEnqueueOnSubscribe(Call originalCall) {
this.originalCall = originalCall;
}
@Override public void call(Subscriber super Response> subscriber) {
// Since Call is a one-shot type, clone it for each new subscriber.
Call call = originalCall.clone();
final CallArbiter arbiter = new CallArbiter<>(call, subscriber);
subscriber.add(arbiter);
subscriber.setProducer(arbiter);
call.enqueue(new Callback() { //调用了OkHttp的enqueue方法执行真正的网络加载。
@Override public void onResponse(Call call, Response response) {
arbiter.emitResponse(response); //发射时间
}
@Override public void onFailure(Call call, Throwable t) {
Exceptions.throwIfFatal(t);
arbiter.emitError(t); //发射onError
}
});
}
}
responseObservable的call方法内部调用了OkHttp来执行真正的网络加载。并且根据返回信息反射对应的时间,使RxJava的观察者可以接收事件。
四、总结
retrofit的源码很值得我们学习,其中包括了各种设计模式,反射,动态代理。看完感叹自己要学得还有很多啊。