簡介
Retrofit 是 Square 推出的類型安全的HTTP框架已亥,用于android和java,封裝了OkHttp来屠,本文簡單介紹用法虑椎,然后分析源碼流程和涉及的設(shè)計(jì)模式。
基本使用
定義API接口俱笛,下面是官方文檔的例子
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
定義接口GitHubService
,創(chuàng)建接口返回值為Call<List<Repo>>
的方法listRepos
捆姜,注解@GET
表示使用GET
方法請(qǐng)求服務(wù)器,@GET注解的value是API接口的相對(duì)路徑迎膜。方法參數(shù)@Path("user") String user
表示使用傳入?yún)?shù)user替換相對(duì)路徑的{user}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService serviceApi = retrofit.create(GitHubService.class);
Call<List<Repo>> call = serviceApi.listRepos("octocat");
call.enqueue(new Callback<List<Repo>>() {
@Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
}
@Override
public void onFailure(Call<List<Repo>> call, Throwable t) {
}
});
- 實(shí)例化Retrofit泥技,Retrofit使用Builder設(shè)計(jì)模式創(chuàng)建,傳入baseUrl和gson轉(zhuǎn)換工廠構(gòu)建Retrofit實(shí)例對(duì)象磕仅。
- create方法傳入API接口class對(duì)象珊豹,返回值是動(dòng)態(tài)代理生成的代理的接口實(shí)現(xiàn)類,使用GitHubService接收榕订。
- 代理接口實(shí)現(xiàn)類調(diào)用定義的listRepos方法平夜,獲取Call
- call.enqueue異步請(qǐng)求接口
源碼分析
源碼分析將按照上方的示例代碼從上往下分析
- 創(chuàng)建Retrofit實(shí)例 (Builder設(shè)計(jì)模式)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
無參Builder會(huì)調(diào)用自身的傳入平臺(tái)的構(gòu)造方法
public Builder() {
this(Platform.get());
}
Platform.get(),判斷當(dāng)前的平臺(tái)為Android還是java
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
return new Platform(true);
}
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Nullable @Override Object invokeDefaultMethod(Method method, Class<?> declaringClass,
Object object, @Nullable Object... args) throws Throwable {
if (Build.VERSION.SDK_INT < 26) {
throw new UnsupportedOperationException(
"Calling default methods on API 24 and 25 is not supported");
}
return super.invokeDefaultMethod(method, declaringClass, object, args);
}
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
Android平臺(tái)defaultCallbackExecutor()
返回MainThreadExecutor
實(shí)例卸亮,MainThreadExecutor
創(chuàng)建了主線程的Handler
,在execute()
方法將Runnable
作為callback
傳入玩裙,切換到主線程
build()方法創(chuàng)建Retrofit 實(shí)例
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//判斷callFactory是否為空兼贸,為空給光桿OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//判斷是否設(shè)置了callbackExecutor段直,沒有使用平臺(tái)默認(rèn),android平臺(tái)默認(rèn)主線程
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//callAdapterFactories中已a(bǔ)dd在builder時(shí)設(shè)置的CallAdapterFactory
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//返回Retrofit實(shí)例
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
build()方法(CallAdapterFactory,ConverterFactory抽象工廠設(shè)計(jì)模式)
- 1.判斷callFactory是否為空溶诞,為空給光桿OkHttpClient
- 2.判斷是否設(shè)置了callbackExecutor鸯檬,沒有就使用平臺(tái)默認(rèn)Executor,android平臺(tái)默認(rèn)主線程
- 3.callAdapterFactories已a(bǔ)dd了通過builder
addCallAdapterFactory()
的適配工廠(如支持RxJava的適配器Factory),添加平臺(tái)默認(rèn)的適配工廠 - 4.converterFactories轉(zhuǎn)換工廠螺垢,已a(bǔ)dd了builder
addConverterFactory()
的轉(zhuǎn)換工廠(如Gson轉(zhuǎn)換工廠) - 創(chuàng)建Retrofit實(shí)例返回
創(chuàng)建ServiceApi代理實(shí)現(xiàn)類(動(dòng)態(tài)代理設(shè)計(jì)模式)
ServiceApi serviceApi = retrofit.create(ServiceApi.class);
public <T> T create(final Class<T> service) {
//驗(yàn)證接口
validateServiceInterface(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 {
// 判斷方法是否屬于Object喧务,如equals、hashCode方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//是否是平臺(tái)默認(rèn)方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//重點(diǎn)
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
動(dòng)態(tài)代理動(dòng)態(tài)創(chuàng)建了接口的代理實(shí)現(xiàn)類枉圃,調(diào)用的接口方法都會(huì)經(jīng)過這個(gè)方法功茴,如果還不是特別了解代理設(shè)計(jì)模式的同學(xué),可結(jié)合我的這篇文章看看代理設(shè)計(jì)模式-從Retrofit的create方法分析動(dòng)態(tài)代理
- 1.驗(yàn)證是否是接口和是否有父接口
- 2.判斷方法是否屬于Object孽亲,如equals坎穿、hashCode方法
- 3.是否是平臺(tái)默認(rèn)方法
- 4.loadServiceMethod(重點(diǎn)方法接下來重點(diǎn)分析)
loadServiceMethod方法(享元設(shè)計(jì)模式)
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
serviceMethodCache是一個(gè)ConcurrentHashMap<Method, ServiceMethod<?>>,key值為method,value值為封裝了請(qǐng)求方法和注解等等ServiceMethod。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
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);
}
abstract @Nullable T invoke(Object[] args);
}
final class RequestFactory {
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
//此處省略大量代碼
static final class Builder {
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(method,
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
if (relativeUrl == null && !gotUrl) {
throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(method, "Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError(method, "Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError(method, "Multipart method must contain at least one @Part.");
}
return new RequestFactory(this);
}
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);
} 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(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
}
RequestFactory.Builder的構(gòu)造方法返劲,獲取了method的方法注解玲昧、返回值類型、參數(shù)注解篮绿。
接下來看 build()方法
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
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);
} 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(method, "@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
遍歷了method注解孵延,用于判斷請(qǐng)求方法和注解是否正確使用。繼續(xù)往下看
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
if (relativeUrl == null && !gotUrl) {
throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(method, "Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError(method, "Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError(method, "Multipart method must contain at least one @Part.");
}
return new RequestFactory(this);
解析了參數(shù)和參數(shù)注解亲配,判斷參數(shù)和注解是否正確使用尘应,返回了RequestFactory實(shí)例∑ィ回到ServiceMethod類繼續(xù)往下分析
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);
獲取方法返回值類型的下面是一些防御性的代碼菩收,不是我們關(guān)注的重點(diǎn),直接來看重點(diǎn)方法HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
//判斷是否用了kotlin協(xié)程鲸睛,這里不關(guān)心娜饵,先忽略,直接看else
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
運(yùn)用了Adapter設(shè)計(jì)模式將okhttp的call轉(zhuǎn)換成retrofit的call官辈,完成了請(qǐng)求參數(shù)的封裝并使用okhttp請(qǐng)求網(wǎng)絡(luò)箱舞,okhttp源碼不在本文的分析范圍,有興趣可以再去了解下了拳亿。
總結(jié)
Retrofit運(yùn)用了大量的設(shè)計(jì)模式晴股,對(duì)okhttp進(jìn)行了高度的定制和功能拓展。是一款比較值得分析網(wǎng)絡(luò)框架