在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是一款非常優秀的網絡請求架構,拓展性非常好。理解這樣的開源框架的源碼,有助於我們擴展視野,以及更好解決在使用過程當中所遇到的問題。