在gradle配置里面是中增加对retrofit的引用。
compile’com.squareup.retrofit2:retrofit:2.2.0’
这篇文章主要分析下retrofit2框架的底层原理。我下载到的是2.2.0的版本。
一.如何使用Retrofit
首先看一下Retrofit是怎么用的。
public interface GithubService{
@GET("user/{user}/repos")
Call<List<ResponseBody>> listRpo(@Path("user") String user)
}
Retrofit tetrofit = new Retrofit.Builder()
.client(new OkHttpClient())
.baseUrl("https://www.github.com/")
.build();
GithubService service = tetrofit.create(GithubService.class)
Call<List<ResponseBody>> call = service.listRpo("octocat");
call.enqueue(new Callback<List<ResponseBody>>() {
@Override
public void onResponse(Call<List<ResponseBody>> call, Response<List<ResponseBody>> response) {
String result = response.getBody();
}
@Override
public void onFailure(Call<List<ResponseBody>> call, Throwable t) {
Log.d("TAG",t.getMessage());
}
});
使用retrofit需要先创建一个interface接口,这个接口其实声明了网络请求的地址,参数,返回类型,请求方式等等。这个接口在retrofit的转化下可以转化成网络请求。retrofit跟其他网络请求框架的最明显不同处,就在于这一点。
当然retrofit支持以下功能:
1.支持@Get和@Post两种访问方式
2.支持添加网络请求头参数
3.请求地址动态配置
因为我们这里主要讲一下它底层原理,所以以上三点就不拓展讲了。
Retrofit大致是以下两步:
1.
构建网络请求——创建一个Retrofit类,这个Retrofit类是用建造者模式构建的。
上面指定了底层是用okhttp进行通讯,并且它的URL是www.github.com。然后获得GithubService对象。这个GithubService就是我们自己定义的接口类,Retrofit会自动将我们定义的接口类转化成网络请求。
2.
发送网络请求——得到call对象,执行call对象。
二.java动态代理
因为retrofit底层是用java动态代理实现的,所以在了解retrofit之前应该先弄懂java动态代理的机制。
关于动态机制,这里有一篇比较好的文章:
http://www.cnblogs.com/xiaoluo501395377/p/3383130.html
三.构建网络请求
接下来从源码的角度来看一下retrofit怎么工作的。
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> adapterFactories;
final Executor callbackExecutor;
final boolean validateEagerly;
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;
}
最核心的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)
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<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
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;
}
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);
}
先来看一下build方法,调用Retrofit.build的build方法会生成一个Retrofit对象,传递给它callFactory, baseUrl, converterFactories, adapterFactories这些参数,这些参数具体有什么用呢,callFacotry是你网络请求采用的底层通信,比如okhttp请求,baseUrl表示请求的地址,converterFactories表示转换器,adapterFactories用来支持rxjava的适配器。
在create方法中首先会进行判断所传入进来的Service是否是一个接口,当我们将validateEagerly属性设为true的时候,在我们调用create方法创建一个Service,就直接调用eagerlyValidateMethods方法。而eagerlyValidateMethods的作用是通过反射获取获们创建service接口中所有的接口方法,然后根据接口方法和当前的retrofit对象来获得ServiceMethod并且以接口方法作为Key,ServiceMethod作为值添加到serviceMethodCache缓存中。这样做的目的是为了下次便可以通过接口方法直接获取ServiceMethod。
接下来用到了java的动态模式,java动态代理的作用是将这个在一段代码的方法执行前插入一段执行的代码。当我们通过自己创建的接口去调用接口方法时,这时候动态代理会去先执行invoke方法。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
这三段关键代码有什么用呢?ServiceMethod负责将自定义接口转化为实际的http请求的一个类。调用servicemehtod的calladapter当中的adapt方法进行初始化。也就是说当我们调用自己实现接口的方法时,Retrofit利用create方法然后通过java动态放射的方式去调用servicemethod当中的calladapter当中的adapt方法进行初始化。这样就得到的动态代理接口看起来是上面自己实现的GithubService,但是通过java动态代理会将这个GithubService在调用方法时转化为真正的http请求。
接下来对上面这三句关键代码进行详细的分析。首先,通过loadServceMethod方法从这个缓存当中获取ServiceMethod。loadServceMethod方法是Retrofit类中的方法,详细回过头看一下就知道了,然后在获取ServiceMethod的时候用到了ServiceMehtod的build()方法。
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();
...//省略代码 return new ServiceMethod<>(this);
}
这个方法返回一个新的ServiceMethod,但是在这之前也创建了 calladapter对象,responseType,responseConvert对象。
createCallAdapter里面默认遍历了Retrofit的adapterFactories,这时需要回过头去看Retrofit类的build方法,Retrofit类在build方法中有一个默认的defaultCallAdapterFactory。
Retrofit在创建的时候,默认的callFactory是OKHttpClient,默认的callbackexecutrot是platform.defaultCallbackExecutor();但是我不知道这个defaultCallbackExecutor到底是哪个类。platform是一个表示当前平台的接口,我找了一会儿源代码,发现这个paltform是一个Android类里实现的,最后,我们在下面这段代码中找到了这个defaultCallbackExecutor.
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);
}
}
}
“`
看第二个方法,defaultCallAdapterFactory这个方法返回的是ExecutorCallAdapterFactory
我们看一下ExecutorCallAdapterFactory的源码。
@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<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
serviceMethod.callAdapter.adapt(okHttpCall); 这句代码最终就是返回了一个ExecutorCallbackCall.
四,发送网络请求
GithubService service = tetrofit.create(GithubService.class)
Call
static final class ExecutorCallbackCall<T> implements Call<T> {
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();
}
ExecutorCallbackCall有enqueue和execute方法,但是具体里面都是交给delegate对象去执行的。那么这个delegate对象又是什么呢?就是serviceMethod.callAdapter.adapt(okHttpCall)里面的okHttpCall,一个实现了Call接口的OkHttpCall对象。如此我们只要研究下OkHttpCall对象就行了。
OkHttpCall对象是访问请求的对象,默认的作用是发送一个HTTP请求,底层是使用了okhttp进行网络通讯。
privateokhttp3.Call createRawCall()throwsIOException {
Request request =serviceMethod.toRequest(args);
okhttp3.Call call =serviceMethod.callFactory.newCall(request);
if(call ==null) {
throw newNullPointerException(“Call.Factory returned null.”);
}
return call;
}
OkHttpCall实现了enqueue和execute方法,这两个方法是真正网络请求发起的方法,都通过调用createRawCall()来创建请求。execute方法是在当前线程执行,将具体执行的动作交给android的okhttp去完成,调用了okhttp3.Call.execute()函数。
enqueue方法是将请求放到一个异步线程队列当中。调用okhttp3.Call.enqueue()函数。
说白了,在默认情况下,我们的retrofit底层还是调用okhttp来实现的。
Ps:可以参考下HttpCall里面的execute方法
@OverridepublicResponse execute() throwsIOException {
okhttp3.Call call;
synchronized(this) {
if(executed)throw newIllegalStateException(“Already executed.”);
executed=true;
if(creationFailure!=null) {
if(creationFailureinstanceofIOException) {
throw(IOException)creationFailure;
}else{
throw(RuntimeException)creationFailure;
}
}
call =rawCall;
if(call ==null) {
try{
call =rawCall= createRawCall();
}catch(IOException | RuntimeException e) {
creationFailure= e;
throwe;
}
}
}
if(canceled) {
call.cancel();
}
returnparseResponse(call.execute());
}
五,支持报文解析
Retrofit还支持Gson解析啊,xml解析技术。使用宽广,十分方便。比如:
Retrofit retrofit = new Retrofit.Builder().
baseUrl(‘https://api.github.com’).
.addConvertFacotry(GsonConverterFactory.create()) //支持报文自动解析
.build
然后构建网络请求:
final MehtodService methdoservice = retrofit.create(MehtodService.class);
发起网络请求
Call call = methdoservice.getMsg();
这个GsonConverterFactory会自动解析你接受的gson格式的报文,在调用网络请求后,转化成为这里的Bean。前提是这个Bean类里面的字段和Gson报文的字段是一样的,这样就能自动解析成功。
增加依赖库的代码:
如果想要增加对xml解析器的支持:
compile(‘com.squareup.retrofit2:converter-simplexml:2.1.0’);
如果想要增加对gson格式解析器的支持:
compile ‘com.squareup.retrofit2:converter-gson:2.0.2’
如果想要增加对rxjava的支持:
compile ‘com.squareup.retrofit2:adapter-rxjava:2.0.2’
也可以通过实现Converter.Factory接口来创建一个自定义的converter。因为addConvertFacotry里面的操作就是往Retrofit这个类中增加Converter.Factory接口.
这个Converter对象是什么时候创建的?首先我们在构建Retrofit的时候传了一个GsonConverterFactory.create(),然后会在ServiceMethod的build()的时候将我们创建的Converter加入进去.关键代码如下:
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();
。。。
}
关键是执行了createResponseConverter()方法,然后查看你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);
}
}
主要执行了responseBodyConverter方法。找到responseBodyConverter方法再看一下()。
public<T> Converter<ResponseBody, T>responseBodyConverter(Type type, Annotation[] annotations) {
看下nextResponseBodyConverter()这里面的逻辑。
returnnextResponseBodyConverter(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;
}
}
。。。
}
关键是执行了从converterFactories当中查找到对应的factory,然后执行responseBodyConverter方法,这个方法如果是自定义的Converter.Factory,就是自定义解析报文格式的话,必须得自己实现这个方法。
四,其他
Retrofit2支持了RxJava的使用。这部分内容也很多,这里就不再拓展开来了。Retrofit是一款非常优秀的网络请求架构,拓展性非常好。理解这样的开源框架的源码,有助于我们扩展视野,以及更好解决在使用过程当中所遇到的问题。