1. Retrofit功能
Retrofit 是一个广泛用于处理网络请求的库,主要用于在 Android 和 Java 应用中进行 HTTP 请求。以下是 Retrofit 的一些主要功能:
-
声明式 API 定义: Retrofit 允许你使用简单的注解来定义 API 接口,使得你可以通过接口声明来描述 HTTP 请求。
lessjavaCopy code public interface ApiService { @GET("user/{id}") Call<User> getUser(@Path("id") int userId); }
-
强大的 URL 拼接: Retrofit 提供了简单而强大的 URL 拼接功能,使得构建复杂的请求 URL 变得容易。
lessjavaCopy code @GET("user/list") Call<List<User>> getUserList(@Query("page") int page, @Query("size") int size);
-
同步和异步请求: Retrofit 支持同步和异步的请求方式,通过
Call
类来执行同步或异步请求。lessjavaCopy code Call<User> call = apiService.getUser(1); // 同步请求 Response<User> response = call.execute(); // 异步请求 call.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { // 处理响应 } @Override public void onFailure(Call<User> call, Throwable t) { // 处理失败 } });
-
灵活的数据转换: Retrofit 支持使用不同的转换器(Converter)来处理请求和响应的数据格式,例如 JSON、XML、ProtoBuf 等。
scssjavaCopy code // 使用 Gson 转换器 Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.example.com/") .addConverterFactory(GsonConverterFactory.create()) .build();
-
动态 URL: Retrofit 允许你在运行时动态地修改请求的 URL,这对于构建动态参数的请求非常有用。
lessjavaCopy code @GET Call<User> getUser(@Url String url); `
-
支持文件上传和下载: Retrofit 提供了方便的方式来处理文件上传和下载。
lessjavaCopy code @Multipart @POST("upload") Call<ResponseBody> uploadFile(@Part MultipartBody.Part filePart);
-
协程的支持:在Retrofit2.9中默认添加了协程的支持,可以定义接口函数为挂起函数。
2 Retrofit设计模式
- 动态代理模式
- 创建者模式
- 工厂模式
- 适配器模式
- 策略模式
3. Retrofit源码解析
3.1 方法上的注解如何解析(函数注解+函数参数注解)
- 解析的入口是ServiceMethod的parseAnnotations方法
java
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
//.....
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
- 通过RequestFactory.parseAnnotations方法获取注解的一系列参数,包括函数注解(GET,POST等),函数参数注解(Path,Query,Url等)。最终返回一个RequestFactory对象,这个对象内部解析并记录了这些参数。 内部Buidler类记录了需要解析的数据:
dart
static final class Builder {
// ....
final Retrofit retrofit;
final Method method;
final Annotation[] methodAnnotations;// 函数注解
final Annotation[][] parameterAnnotationsArray; //函数参数注解
final Type[] parameterTypes;//参数类型
// ....
}
函数注解和函数参数注解处理过程:
java
RequestFactory 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);
}
.....
}
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);
}
// 处理函数参数注解
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
result = annotationAction;
}
}
3.2 创建Okhttp请求过程,在RequestFactory中实现
ini
okhttp3.Request create(Object[] args) throws IOException {
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args.length;
RequestBuilder requestBuilder =
new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
if (isKotlinSuspendFunction) {
// The Continuation is the last parameter and the handlers array contains null at that index.
argumentCount--;
}
List<Object> argumentList = new ArrayList<>(argumentCount);
for (int p = 0; p < argumentCount; p++) {
argumentList.add(args[p]);
// 之前函数参数的注解处理过程,将所有的注解都处理成一个ParameterHandler对象,每个特定注解都会继承ParameterHandler类,实现apply方法
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
例如,Header注解最终处理交给了Header类,实现的apply方法作用是添加请求的头部信息,以注解的参数为key,注解的值为value。
java
static final class Header<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
Header(String name, Converter<T, String> valueConverter) {
this.name = Objects.requireNonNull(name, "name == null");
this.valueConverter = valueConverter;
}
@Override
void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String headerValue = valueConverter.convert(value);
if (headerValue == null) return; // Skip converted but null values.
builder.addHeader(name, headerValue);
}
}
3.3 CallAdapter作用以及实现
CallAdapter的作用是将Call对象转换成自定义的对象,成应用程序中所需要的其他类型,通常是某种回调、响应类型或者异步操作,比如Rxjava的观察者。CallAdapter接口中转换方法的定义:
java
public interface CallAdapter<R, T> {
Type responseType();
T adapt(Call<R> call);
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
默认的实现是DefaultCallAdapterFactory
。执行流程是在Retofit中loadServiceMethod(service, method).invoke(args)
会执行HttpServiceMethod的invoke方法,再执行adapt
方法,后在实现类CallAdapted
中调用CallAdapter的adapt方法。
3.4 Converter转换成JavaBean的过程
在HttpServiceMethod中注册了Converter<ResponseBody, ResponseT> responseConverter
对象,通过上述CallAdapter的转换最终执行到OkHttpCall
类的parseResponse
方法中,该方法执行T body = responseConverter.convert(catchingBody);
会执行转换成javabean的逻辑。 转换器Converter接口定义如下:
java
public interface Converter<F, T> {
@Nullable
T convert(F value) throws IOException;
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, RequestBody> requestBodyConverter(
Type type,
Annotation[] parameterAnnotations,
Annotation[] methodAnnotations,
Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, String> stringConverter(
Type type, Annotation[] annotations, Retrofit retrofit) {
return null;
}
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
}
3.5 动态代理使用
Java 动态代理通过运行时生成代理类和对象
,使得可以在运行时动态地为被代理的对象添加额外的行为,实现了一些灵活的编程模式。在执行被代理方法的时候,会执行InvocationHandler的invoke方法,并传入被代理对象和Method对象和参数表。 这里的动态代理是将所有定义在service接口中方法都代理到下面的invoke方法中,在逐步解析注解,创建请求,解析转换成javabean。
java
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[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// 如果是Object中定义的方法直接走原来实现
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 排除掉java8,java8接口默认可以有实现
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
3.6 协程处理
如果是挂起函数,会执行下面的SuspendForResponse
类来处理CallAdapter
,SuspendForResponse
是HttpServiceMethod
的子类重写了adapt方法。由于挂起函数实际原理是将协程对象加入到最后一位函数参数中,也就是kotlin.coroutines.Continuation
对象。这里获取这各对象再执行awaitResponse
方法,这是一个扩充类方法,实现最终的enqueue请求。
java
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
SuspendForResponse(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call);
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1];
// See SuspendForBody for explanation about this try/catch.
try {
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) {
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
awaitResponse方法源码
kotlin
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}