ServiceMethod 分析
1. 创建动态代理对象
在 Retrofit 中,通过 Retrofit#create 方法可以创建接口的动态代理实现,使得接口方法的调用能够被拦截并进入指定的处理逻辑。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
// 创建 ServiceMethod 对象,通过ServiceMethod解析方法注解及方法参数
ServiceMethod serviceMethod = loadServiceMethod(method);
// 创建 OkHttpCall 实例来处理 HTTP 请求
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 接收一个 `okHttpCall` 对象作为参数,并返回 Call 对象
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
- Proxy.newProxyInstance() 方法: 创建动态代理对象,需要指定类加载器、实现的接口数组和
InvocationHandler对象,用于处理方法调用。 - InvocationHandler.invoke() 方法: 当代理实例上的方法被调用时执行,负责拦截方法调用并进行相应处理。
- ServiceMethod 对象创建: 通过
loadServiceMethod()方法解析方法的注解,创建包含 HTTP 请求详细信息的ServiceMethod对象。 - OkHttpCall 对象创建: 使用
ServiceMethod对象和方法参数创建OkHttpCall实例,用于执行 HTTP 请求。 - CallAdapter 对象创建: 在
ServiceMethod的build方法中创建CallAdapter对象,用于将OkHttpCall适配为接口方法的返回类型。 - callAdapter.adapt(okHttpCall): 它接收一个
okHttpCall对象作为参数,并返回 Call 对象。代码示例中的Call<User> call就是通过callAdapter.adapt(okHttpCall)方法返回的。
loadServiceMethod() 方法
loadServiceMethod 方法用于加载并缓存 ServiceMethod 对象,以提高效率并避免重复创建对象。
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
ServiceMethod loadServiceMethod(Method method) {
synchronized (serviceMethodCache) {
ServiceMethod result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
return result;
}
}
说明:
-
缓存机制: 使用
LinkedHashMap作为缓存容器,以方法Method对象作为键,ServiceMethod对象作为值。 -
同步锁: 使用
synchronized关键字保证线程安全,在多线程环境下防止并发访问问题。 -
创建新的 ServiceMethod 对象: 如果缓存中不存在对应的
ServiceMethod对象,则通过ServiceMethod.Builder创建新的对象并存入缓存。 -
返回结果: 返回已存在的或新创建的
ServiceMethod对象,确保每个方法只被解析一次并缓存。
ServiceMethod 类详细分析
ServiceMethod 类负责解析方法的注解,并根据注解信息生成 HTTP 请求的详细信息。
final class ServiceMethod<T> {
private final Retrofit retrofit;
private final Method method;
private final Annotation[] methodAnnotations;
private final Type[] parameterTypes;
private final Annotation[][] parameterAnnotationsArray;
// 其他成员变量省略
// 构造方法
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
// 构建 ServiceMethod 对象
public ServiceMethod build() {
// 创建调用适配器
callAdapter = createCallAdapter();
// 获取响应类型 (responseType)
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)
responseConverter = createResponseConverter();
// 解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 处理方法参数
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
// 解析参数注解
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
// 其他方法和内部类省略
}
说明:
-
Builder 构造方法: 初始化
ServiceMethod对象的各项属性,包括 Retrofit 实例、方法对象、方法的注解数组和参数类型数组。 -
build() 方法: 构建
ServiceMethod对象的过程,包括创建调用适配器、获取响应类型、创建响应转换器、解析方法注解以及处理方法参数。 -
解析方法注解 (
parseMethodAnnotation()方法): 根据不同的 HTTP 方法注解,解析出对应的 HTTP 方法和路径信息。 -
处理方法参数: 遍历方法的参数注解数组,通过
parseParameter()方法解析每个参数的注解信息,并构建相应的ParameterHandler对象。 -
通过 Builder 模式封装对象构建过程: 提供了灵活和可扩展的方式,使得 Retrofit 可以根据接口方法的注解动态地生成并配置每个请求的处理逻辑。
ServiceMethod解析参数过程
在 Retrofit 的 ServiceMethod 类中,参数解析过程涉及多个方法,每个方法负责解析不同类型的注解或参数信息。下面逐一分析这些方法的具体作用和实现细节:
1. parseMethodAnnotation 方法
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);
}
// 其他 HTTP 方法的解析,如 POST、PUT 等
}
-
作用: 解析方法上的 HTTP 方法注解(如
GET、POST、PUT、DELETE等),并根据注解提供的值解析 HTTP 方法和路径信息。 -
实现细节:
- 根据注解类型判断当前 HTTP 方法。
- 调用
parseHttpMethodAndPath方法设置 HTTP 方法、路径信息和是否有请求体(body)的标志。
2. parseHttpMethodAndPath 方法
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.", this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (!value.isEmpty()) {
// 解析相对 URL 路径
this.relativeUrl = value;
// 解析路径参数名称
this.relativeUrlParamNames = parsePathParameters(value);
}
}
-
作用: 解析 HTTP 方法和路径注解,并设置到当前
ServiceMethod对象中。 -
实现细节:
- 检查是否已经设置了 HTTP 方法,如果已设置则抛出异常。
- 设置当前 HTTP 方法类型和是否有请求体的标志。
- 如果提供了路径值,则解析相对 URL 路径,并提取路径参数的名称。
3. parseHeaders 方法
private void parseHeaders(String[] headers) {
if (headers != null) {
for (String header : headers) {
int colon = header.indexOf(':');
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw methodError("@Headers value must be in the form "Name: Value". Found: "%s"", header);
}
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
if ("Content-Type".equalsIgnoreCase(headerName)) {
this.contentType = MediaType.parse(headerValue);
} else {
if (this.headers == null) {
this.headers = new Headers.Builder();
}
this.headers.add(headerName, headerValue);
}
}
}
}
-
作用: 解析方法上的
@Headers注解,并将解析结果设置到当前ServiceMethod对象中的请求头部信息。 -
实现细节:
- 遍历
@Headers注解中的每个字符串。 - 检查每个字符串是否符合 "Name: Value" 的格式,如果不符则抛出异常。
- 解析出头部的名称和值,如果是
Content-Type头部则解析为MediaType对象;否则添加到请求头部中。
- 遍历
4. parseParameter 方法
private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction != null) {
if (result != null) {
throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
if (result == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
return result;
}
-
作用: 解析方法参数上的 Retrofit 注解,并根据不同的注解类型创建对应的
ParameterHandler对象。 -
实现细节:
- 遍历参数的所有注解。
- 对每个注解调用
parseParameterAnnotation方法解析,得到对应的ParameterHandler对象。 - 如果找到多个 Retrofit 注解则抛出异常。
- 如果没有找到 Retrofit 注解则抛出异常。
5. parseParameterAnnotation 方法
private ParameterHandler<?> parseParameterAnnotation(int p, Type parameterType, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Query) {
// 解析 @Query 注解
// 验证参数类型是否可解析
validateResolvableType(p, type);
// 获取 @Query 注解的属性值
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
// 获取参数的原始类型
Class<?> rawParameterType = Utils.getRawType(type);
// 标记已经获取了 @Query 注解
gotQuery = true;
// 处理 Iterable 类型的参数
if (Iterable.class.isAssignableFrom(rawParameterType)) {
// 如果参数是 Iterable 类型,则需要检查是否包含泛型类型
if (!(type instanceof ParameterizedType)) {
throw parameterError(
method,
p,
rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
// 获取 Iterable 的泛型类型
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
// 创建转换器来将泛型类型转换为 String
Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
// 返回一个处理 Iterable 类型参数的 ParameterHandler.Query 对象
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (annotation instanceof Path) {
// 解析 @Path 注解
return parseParameterPath(p, parameterType, annotations);
} else if (annotation instanceof Header) {
// 解析 @Header 注解
return parseParameterHeader(p, parameterType, annotations);
} else if (annotation instanceof Field) {
// 解析 @Field 注解
return parseParameterField(p, parameterType, annotations);
} else if (annotation instanceof Part) {
// 解析 @Part 注解
return parseParameterPart(p, parameterType, annotations);
} else if (annotation instanceof Body) {
// 解析 @Body 注解
return parseParameterBody(p, parameterType, annotations);
} else {
return null; // 其他情况返回 null
}
}
-
作用: 根据特定的 Retrofit 注解类型,解析方法参数的注解并创建对应的
ParameterHandler对象。 -
实现细节:
- 根据
annotation的类型判断具体的 Retrofit 注解类型(如@Query、@Path、@Header等)。 - 如果
annotation不是 Retrofit 的注解之一,则返回 null。
- 根据