目录
- 序章
- Retrofit构建过程
- 创建网络请求接口实例过程
- 执行请求过程
- 总结
序章
首先引入依赖
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
在原理之前,我们先来回忆一下Retrofit的基本使用
1、定义接口
interface MyService { | |
@GET("gallery/{imageType}/response") | |
fun getImages(@Path("imageType") imageType: String): Call<List<String>> | |
} |
2、构建Retrofit,创建网络请求接口类实例
val retrofit = Retrofit.Builder() | |
.baseUrl(BASE_URL) | |
.build() | |
val myService = retrofit.create(MyService::class.java) |
3、生成Call,执行请求
val resp = myService.getImages("banner") | |
resp.enqueue(object : Callback<List<String>> { | |
override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) { | |
TODO("Not yet implemented") | |
} | |
override fun onFailure(call: Call<List<String>>, t: Throwable) { | |
TODO("Not yet implemented") | |
} | |
}) |
这样一个基本的网络请求就搞定了,使用很简洁,正是因为其内部使用了大量的设计模式和优秀的架构设计,才得以使其如此方便地进行网络请求,下面我们就一起来探索探索Retrofit的设计之美。
Retrofit构建过程
使用了建造者模式通过内部静态类Builder构建一个Retrofit实例,这里只列出了部分方法,其他类似
public static final class Builder { | |
private final Platform platform; | |
// 网络请求工厂,工厂方法模式 | |
private okhttp.Call.Factory callFactory; | |
// 网络请求地址 | |
private HttpUrl baseUrl; | |
// 数据转换器工厂的集合 | |
private final List<Converter.Factory> converterFactories = new ArrayList<>(); | |
// 网络请求适配器工厂的集合,默认是ExecutorCallAdapterFactory | |
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); | |
// 回调方法执行器,用于切换线程 | |
private Executor callbackExecutor; | |
// 一个开关,为true则会缓存创建的ServiceMethod | |
private boolean validateEagerly; | |
//...... | |
public Builder baseUrl(String baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null"); | |
return baseUrl(HttpUrl.get(baseUrl)); | |
} | |
public Builder baseUrl(HttpUrl baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null"); | |
List<String> pathSegments = baseUrl.pathSegments();if (!"".equals(pathSegments.get(pathSegments.size() -))) { | |
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); | |
}this.baseUrl = baseUrl; | |
return this; | |
} | |
// 将一个含有Gson对象实例的GsonConverterFactory放入数据转换器工厂 | |
public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(Objects.requireNonNull(factory, "factory == null")); | |
return this; | |
} | |
//...... | |
} |
通过build,我们上面Builder类中的参数对象都配置到了Retrofit对象中。
public Retrofit build() { | |
if (baseUrl == null) { | |
throw new IllegalStateException("Base URL required."); | |
} | |
okhttp.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> callAdapterFactories = new ArrayList<>(this.callAdapterFactories); | |
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor)); | |
// Make a defensive copy of the converters. | |
List<Converter.Factory> converterFactories = | |
new ArrayList<>( + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); | |
// Add the built-in converter factory first. This prevents overriding its behavior but also | |
// ensures correct behavior when using converters that consume all types. | |
converterFactories.add(new BuiltInConverters()); | |
converterFactories.addAll(this.converterFactories); | |
converterFactories.addAll(platform.defaultConverterFactories()); | |
return new Retrofit( | |
callFactory, | |
baseUrl, | |
unmodifiableList(converterFactories), | |
unmodifiableList(callAdapterFactories), | |
callbackExecutor, | |
validateEagerly); | |
} |
创建网络请求接口实例过程
使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例。
public <T> T create(final Class<T> service) { 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[]; | |
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); | |
} | |
args = args != null ? args : emptyArgs; | |
return platform.isDefaultMethod(method) | |
? platform.invokeDefaultMethod(method, service, proxy, args) | |
: loadServiceMethod(method).invoke(args); | |
} | |
}); | |
} |
跟踪 loadServiceMethod,parseAnnotations解析注解配置得到ServiceMethod,然后加入到serviceMethodCache缓存中,是一个ConcurrentHashMap。
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; | |
} | |
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); | |
} |
执行请求过程
public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); | |
okhttp.Call call; | |
Throwable failure; | |
synchronized (this) { | |
if (executed) throw new IllegalStateException("Already executed."); | |
executed = true; | |
call = rawCall; | |
failure = creationFailure; | |
if (call == null && failure == null) { | |
try { | |
// 创建一个OkHttp的Request对象请求 | |
call = rawCall = createRawCall(); | |
} catch (Throwable t) { | |
throwIfFatal(t); | |
failure = creationFailure = t; | |
} | |
} | |
} | |
if (failure != null) { | |
callback.onFailure(this, failure); | |
return; | |
} | |
if (canceled) { | |
call.cancel(); | |
} | |
call.enqueue( | |
new okhttp.Callback() { | |
public void onResponse(okhttp.Call call, okhttp3.Response rawResponse) { | |
Response<T> response; | |
try { | |
// 解析网络请求返回的数据 | |
response = parseResponse(rawResponse); | |
} catch (Throwable e) { | |
throwIfFatal(e); | |
callFailure(e); | |
return; | |
} | |
try { | |
callback.onResponse(OkHttpCall.this, response); | |
} catch (Throwable t) { | |
throwIfFatal(t); | |
t.printStackTrace(); // TODO this is not great | |
} | |
} | |
public void onFailure(okhttp.Call call, IOException e) { | |
callFailure(e); | |
} | |
private void callFailure(Throwable e) { | |
try { | |
callback.onFailure(OkHttpCall.this, e); | |
} catch (Throwable t) { | |
throwIfFatal(t); | |
t.printStackTrace(); // TODO this is not great | |
} | |
} | |
}); | |
} | |
Response<T> parseResponse(okhttp.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); | |
// Remove the body's source (the only stateful object) so we can pass the response along. | |
rawResponse = | |
rawResponse | |
.newBuilder() | |
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) | |
.build(); | |
int code = rawResponse.code(); | |
// 根据响应返回的状态码进行处理 | |
if (code < || code >= 300) { | |
try { | |
// Buffer the entire body to avoid future I/O. | |
ResponseBody bufferedBody = Utils.buffer(rawBody); | |
return Response.error(bufferedBody, rawResponse); | |
} finally { | |
rawBody.close(); | |
} | |
} | |
if (code == || code == 205) { | |
rawBody.close(); | |
return Response.success(null, rawResponse); | |
} | |
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); | |
try { | |
// 将响应体转为Java对象 | |
T body = responseConverter.convert(catchingBody); | |
return Response.success(body, rawResponse); | |
} catch (RuntimeException e) { | |
// If the underlying source threw an exception, propagate that rather than indicating it was | |
// a runtime exception. | |
catchingBody.throwIfCaught(); | |
throw e; | |
} | |
} |
总结
首先,使用建造者模式通过Builder构建一个Retrofit实例,Builder类中的参数对象都配置到Retrofit对象中,然后使用动态代理的方式拿到所有注解配置后,创建网络请求接口实例,生成OkHttp请求,通过callAdapterFactory找到对应的执行器,比如RxJava2CallAdapterFactory,最后通过ConverterFactory将返回数据解析成JavaBean,使用者只需关心请求参数,内部实现由Retrofit封装完成,底层请求还是基于okhttp实现的。