在现代 Android 和 Java 开发中,网络请求是不可或缺的一部分。Retrofit 作为 Square 公司开源的一款强大的类型安全的 HTTP 客户端,凭借其简洁易用的 API 和高效的性能,在开发者社区中广受欢迎。Retrofit 的核心特性之一便是通过注解来定义 HTTP 请求,这种方式使得代码更加清晰、易读且易于维护。本文将深入 Retrofit 框架的源码,对其注解定义与解析模块进行全面且细致的分析,揭示其背后的实现原理。
Retrofit 的主要工作流程可以概括为以下几个步骤:
Retrofit.Builder
构建 Retrofit 实例,配置请求的基础 URL、转换器工厂、调用适配器工厂等。注解在 Retrofit 中扮演着至关重要的角色,它们用于描述 HTTP 请求的各个方面,包括请求方法(如 GET、POST 等)、请求路径、请求参数、请求头、请求体等。通过注解,开发者可以以一种声明式的方式定义请求,而无需编写繁琐的网络请求代码。
@GET
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 表示 HTTP GET 请求的注解
*/
@Documented
// 该注解只能应用于方法上
@Target(ElementType.METHOD)
// 该注解在运行时保留,以便通过反射获取
@Retention(RetentionPolicy.RUNTIME)
public @interface GET {
/**
* 指定请求的相对路径
* @return 请求的相对路径,默认为空字符串
*/
String value() default "";
}
@GET
注解用于标记一个方法为 HTTP GET 请求,value
属性用于指定请求的相对路径。例如:
java
public interface ApiService {
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
}
除了 @GET
注解,Retrofit 还提供了 @POST
、@PUT
、@DELETE
、@HEAD
、@OPTIONS
和 @PATCH
等注解,它们的定义方式与 @GET
注解类似,只是用于不同的 HTTP 请求方法。
@Path
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于替换 URL 中占位符的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Path {
/**
* 指定 URL 中的占位符名称
* @return 占位符名称
*/
String value();
/**
* 指定是否对参数进行 URL 编码,默认为 false
* @return 是否进行 URL 编码
*/
boolean encoded() default false;
}
@Path
注解用于替换 URL 中的占位符,例如在上面的 getUser
方法中,@Path("id")
表示将 userId
参数的值替换到 URL 中的 {id}
占位符处。
@Query
和 @QueryMap
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加查询参数到 URL 中的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Query {
/**
* 指定查询参数的名称
* @return 查询参数的名称
*/
String value();
/**
* 指定是否对参数进行 URL 编码,默认为 false
* @return 是否进行 URL 编码
*/
boolean encoded() default false;
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多个查询参数到 URL 中的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryMap {
/**
* 指定是否对参数进行 URL 编码,默认为 false
* @return 是否进行 URL 编码
*/
boolean encoded() default false;
}
@Query
注解用于添加单个查询参数到 URL 中,@QueryMap
注解用于添加多个查询参数。例如:
java
public interface ApiService {
@GET("search")
Call<List<Item>> search(@Query("keyword") String keyword, @Query("page") int page);
@GET("search")
Call<List<Item>> searchWithMap(@QueryMap Map<String, String> queryParams);
}
@Header
和 @HeaderMap
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加请求头的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Header {
/**
* 指定请求头的名称
* @return 请求头的名称
*/
String value();
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多个请求头的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderMap {
}
@Header
注解用于添加单个请求头,@HeaderMap
注解用于添加多个请求头。例如:
java
public interface ApiService {
@GET("data")
Call<Data> getData(@Header("Authorization") String token);
@GET("data")
Call<Data> getDataWithMap(@HeaderMap Map<String, String> headers);
}
@Body
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于指定请求体的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Body {
}
@Body
注解用于指定请求体,通常用于 POST、PUT 等请求。例如:
java
public interface ApiService {
@POST("users")
Call<User> createUser(@Body User user);
}
@FormUrlEncoded
、@Field
和 @FieldMap
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标记表单编码请求的注解
*/
@Documented
// 该注解只能应用于方法上
@Target(ElementType.METHOD)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface FormUrlEncoded {
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加表单字段的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
/**
* 指定表单字段的名称
* @return 表单字段的名称
*/
String value();
/**
* 指定是否对参数进行 URL 编码,默认为 false
* @return 是否进行 URL 编码
*/
boolean encoded() default false;
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多个表单字段的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldMap {
/**
* 指定是否对参数进行 URL 编码,默认为 false
* @return 是否进行 URL 编码
*/
boolean encoded() default false;
}
@FormUrlEncoded
注解用于标记一个方法为表单编码请求,@Field
注解用于添加单个表单字段,@FieldMap
注解用于添加多个表单字段。例如:
java
public interface ApiService {
@FormUrlEncoded
@POST("login")
Call<LoginResponse> login(@Field("username") String username, @Field("password") String password);
@FormUrlEncoded
@POST("login")
Call<LoginResponse> loginWithMap(@FieldMap Map<String, String> fields);
}
@Multipart
、@Part
和 @PartMap
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于标记多部分请求的注解
*/
@Documented
// 该注解只能应用于方法上
@Target(ElementType.METHOD)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Multipart {
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多部分请求中的一个部分的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Part {
/**
* 指定部分的名称
* @return 部分的名称
*/
String value() default "";
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多部分请求中的多个部分的注解
*/
@Documented
// 该注解只能应用于方法的参数上
@Target(ElementType.PARAMETER)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface PartMap {
}
@Multipart
注解用于标记一个方法为多部分请求,@Part
注解用于添加多部分请求中的一个部分,@PartMap
注解用于添加多部分请求中的多个部分。多部分请求常用于文件上传等场景。例如:
java
public interface ApiService {
@Multipart
@POST("upload")
Call<UploadResponse> uploadFile(@Part("file"; filename="image.jpg"") RequestBody file);
@Multipart
@POST("upload")
Call<UploadResponse> uploadFiles(@PartMap Map<String, RequestBody> files);
}
@Headers
注解java
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用于添加多个请求头的注解
*/
@Documented
// 该注解只能应用于方法上
@Target(ElementType.METHOD)
// 该注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface Headers {
/**
* 指定请求头的数组
* @return 请求头的数组
*/
String[] value();
}
@Headers
注解用于在方法上添加多个请求头。例如:
java
public interface ApiService {
@Headers({
"Content-Type: application/json",
"Authorization: Bearer token123"
})
@GET("data")
Call<Data> getData();
}
ServiceMethod
类ServiceMethod
是 Retrofit 中解析注解的核心类,它负责将接口方法上的注解信息解析为实际的 HTTP 请求信息。以下是 ServiceMethod
类的部分源码:
java
abstract class ServiceMethod<T> {
/**
* 解析接口方法上的注解,创建 ServiceMethod 实例
* @param retrofit Retrofit 实例
* @param method 接口方法
* @param 响应类型
* @return ServiceMethod 实例
*/
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 创建 RequestFactory.Builder 实例,用于构建 RequestFactory
RequestFactory.Builder requestFactoryBuilder = new RequestFactory.Builder(retrofit, method);
// 解析请求方法和路径相关的注解
requestFactoryBuilder.parseMethodAnnotation(method.getAnnotations());
// 获取方法的参数类型
Type[] parameterTypes = method.getGenericParameterTypes();
// 获取方法的参数注解
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();
// 遍历方法的每个参数
for (int p = 0; p < parameterTypes.length; p++) {
// 解析参数的注解
requestFactoryBuilder.parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
// 构建 RequestFactory 实例
RequestFactory requestFactory = requestFactoryBuilder.build();
// 获取方法的返回类型
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.");
}
// 创建 CallAdapter 实例,用于将 Call 对象转换为其他类型
CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method, returnType, requestFactory);
// 获取响应类型
Type responseType = callAdapter.responseType();
if (Utils.hasUnresolvableType(responseType)) {
throw methodError(method, "Call return type must not include a type variable or wildcard: %s", returnType);
}
// 创建 Converter 实例,用于将响应数据转换为指定类型
Converter<ResponseBody, T> responseConverter =
createResponseConverter(retrofit, method, responseType);
// 获取 OkHttpClient 实例
okhttp3.Call.Factory callFactory = retrofit.callFactory();
// 创建 ServiceMethod 实例
return new HttpServiceMethod<>(callFactory, requestFactory, callAdapter, responseConverter);
}
/**
* 创建 CallAdapter 实例
* @param retrofit Retrofit 实例
* @param method 接口方法
* @param returnType 方法的返回类型
* @param requestFactory 请求工厂
* @param 响应类型
* @return CallAdapter 实例
*/
private static <T> CallAdapter<T, ?> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, RequestFactory requestFactory) {
try {
// 通过 Retrofit 实例获取 CallAdapter.Factory 列表,并调用其 get 方法创建 CallAdapter 实例
return (CallAdapter<T, ?>) retrofit.callAdapter(returnType, method.getAnnotations());
} catch (RuntimeException e) {
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
/**
* 创建响应转换器实例
* @param retrofit Retrofit 实例
* @param method 接口方法
* @param responseType 响应类型
* @param 响应类型
* @return 响应转换器实例
*/
private static <T> Converter<ResponseBody, T> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
try {
// 通过 Retrofit 实例获取 Converter.Factory 列表,并调用其 responseBodyConverter 方法创建响应转换器实例
return retrofit.responseBodyConverter(responseType, method.getAnnotations());
} catch (RuntimeException e) {
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
/**
* 抽象方法,用于执行请求
* @param args 方法参数
* @return 响应结果
*/
abstract @Nullable T invoke(Object[] args);
}
parseAnnotations
方法是解析的入口,它接收 Retrofit
实例和 Method
实例作为参数,通过以下步骤完成注解解析:
RequestFactory.Builder
实例,用于构建 RequestFactory
。requestFactoryBuilder.parseMethodAnnotation
方法解析请求方法和路径相关的注解。requestFactoryBuilder.parseParameter
方法解析参数的注解。RequestFactory
实例。CallAdapter
实例,用于将 Call
对象转换为其他类型。Converter
实例,用于将响应数据转换为指定类型。OkHttpClient
实例,并创建 ServiceMethod
实例。RequestFactory.Builder.parseMethodAnnotation
方法java
static final class Builder {
// 存储请求方法(如 GET、POST 等)
private String httpMethod;
// 存储请求是否需要请求体
private boolean hasBody;
// 存储请求的相对路径
private String relativeUrl;
// 存储请求的请求头
private okhttp3.Headers headers;
// 存储路径中的占位符名称
private List<String> relativeUrlParamNames;
// 标记是否为多部分请求
private boolean isMultipart;
// 标记是否为表单编码请求
private boolean isFormEncoded;
/**
* 解析请求方法和路径相关的注解
* @param annotations 方法上的注解数组
*/
void parseMethodAnnotation(Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (annotation instanceof HttpMethod) {
// 如果注解是 HttpMethod 类型(如 @GET、@POST 等)
HttpMethod httpMethodAnnotation = (HttpMethod) annotation;
// 获取请求方法
this.httpMethod = httpMethodAnnotation.value();
// 判断是否需要请求体
this.hasBody = httpMethodAnnotation.hasBody();
String path = httpMethodAnnotation.path();
if (!path.isEmpty()) {
// 检查路径是否以 / 开头
if (path.startsWith("/")) {
throw methodError(method, "@%s path must not start with /: %s",
httpMethodAnnotation.annotationType().getSimpleName(), path);
}
this.relativeUrl = path;
// 解析路径中的占位符
this.relativeUrlParamNames = parsePathParameters(path);
}
} else if (annotation instanceof Headers) {
// 如果注解是 Headers 类型
String[] headersToParse = ((Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(method, "@Headers annotation is empty.");
}
// 解析请求头
this.headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
// 如果注解是 Multipart 类型
if (this.hasBody) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
this.isMultipart = true;
this.hasBody = true;
} else if (annotation instanceof FormUrlEncoded) {
// 如果注解是 FormUrlEncoded 类型
if (this.hasBody) {
throw methodError(method, "Only one encoding annotation is allowed.");
}
this.isFormEncoded = true;
this.hasBody = true;
}
}
if (httpMethod == null) {
throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
}
/**
* 解析路径中的占位符
* @param path 请求路径
* @return 占位符名称列表
*/
private static List<String> parsePathParameters(String path) {
// 定义正则表达式,用于匹配路径中的占位符
Matcher m = PARAM_URL_REGEX.matcher(path);
List<String> patterns = new ArrayList<>();
while (m.find()) {
String name = m.group(1);
if (name == null) {
continue;
}
if (patterns.contains(name)) {
throw new IllegalArgumentException("URL path "" + path + "" has duplicate param "" + name + "".");
}
patterns.add(name);
}
return patterns;
}
/**
* 解析请求头
* @param headers 请求头数组
* @return OkHttp 的 Headers 实例
*/
private static okhttp3.Headers parseHeaders(String[] headers) {
okhttp3.Headers.Builder builder = new okhttp3.Headers.Builder();
for (String header : headers) {
int colon = header.indexOf(':');
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw new IllegalArgumentException("Headers value must be in the form "Name: Value". Found: "" + header + """);
}
String name = header.substring(0, colon).trim();
String value = header.substring(colon + 1).trim();
builder.add(name, value);
}
return builder.build();
}
}
parseMethodAnnotation
方法遍历方法上的所有注解,根据注解的类型进行不同的处理:
HttpMethod
类型(如 @GET
、@POST
等),获取请求方法、判断是否需要请求体,并解析路径中的占位符。Headers
类型,解析请求头。Multipart
类型,标记为多部分请求。FormUrlEncoded
类型,标记为表单编码请求。RequestFactory.Builder.parseParameter
方法java
static final class Builder {
// 存储参数处理器数组
private ParameterHandler<?>[] parameterHandlers;
/**
* 解析方法参数的注解
* @param p 参数索引
* @param parameterType 参数类型
* @param annotations 参数上的注解数组
*/
void parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations) {
if (annotations == null) {
throw parameterError(method, p, "No Retrofit annotation found.");
}
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
// 创建参数处理器
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(method, p, "No Retrofit annotation found.");
}
// 将参数处理器添加到参数处理器数组中
parameterHandlers[p] = result;
}
/**
* 解析单个参数注解
* @param p 参数索引
* @param type 参数类型
* @param annotations 参数上的注解数组
* @param annotation 当前要解析的注解
* @return 参数处理器
*/
private @Nullable ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Path) {
// 如果注解
RequestFactory.Builder.parseParameter
方法(续)java
static final class Builder {
// 存储参数处理器数组
private ParameterHandler<?>[] parameterHandlers;
/**
* 解析方法参数的注解
* @param p 参数索引
* @param parameterType 参数类型
* @param annotations 参数上的注解数组
*/
void parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations) {
if (annotations == null) {
throw parameterError(method, p, "No Retrofit annotation found.");
}
ParameterHandler<?> result = null;
for (Annotation annotation : annotations) {
// 创建参数处理器
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
if (result == null) {
throw parameterError(method, p, "No Retrofit annotation found.");
}
// 将参数处理器添加到参数处理器数组中
parameterHandlers[p] = result;
}
/**
* 解析单个参数注解
* @param p 参数索引
* @param type 参数类型
* @param annotations 参数上的注解数组
* @param annotation 当前要解析的注解
* @return 参数处理器
*/
private @Nullable ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Path) {
// 如果注解是 Path 类型
Path path = (Path) annotation;
// 检查路径中是否包含该占位符
if (!relativeUrlParamNames.contains(path.value())) {
throw parameterError(method, p, "@Path parameter "" + path.value()
+ "" not found in relative URL "" + relativeUrl + """);
}
// 检查参数类型是否为基本类型或字符串
if (Utils.hasUnresolvableType(type)) {
throw parameterError(method, p,
"@Path parameter type must not include a type variable or wildcard: %s", type);
}
// 创建 PathParameterHandler 实例
return new ParameterHandler.Path<>(path.value(), path.encoded(),
converterFactory.stringConverter(type, annotations, retrofit));
} else if (annotation instanceof Query) {
// 如果注解是 Query 类型
Query query = (Query) annotation;
// 检查参数类型是否为基本类型或字符串
if (Utils.hasUnresolvableType(type)) {
throw parameterError(method, p,
"@Query parameter type must not include a type variable or wildcard: %s", type);
}
// 创建 QueryParameterHandler 实例
return new ParameterHandler.Query<>(query.value(), query.encoded(),
converterFactory.stringConverter(type, annotations, retrofit));
} else if (annotation instanceof QueryMap) {
// 如果注解是 QueryMap 类型
if (!Map.class.isAssignableFrom(Utils.getRawType(type))) {
throw parameterError(method, p, "@QueryMap parameter type must be Map.");
}
Type keyType = Utils.getSupertype(type, Map.class, String.class);
if (keyType != String.class) {
throw parameterError(method, p, "@QueryMap keys must be of type String: %s", type);
}
Type valueType = Utils.getSupertype(type, Map.class, Object.class);
// 创建 QueryMapParameterHandler 实例
return new ParameterHandler.QueryMap<>(
converterFactory.stringConverter(valueType, annotations, retrofit));
} else if (annotation instanceof Header) {
// 如果注解是 Header 类型
Header header = (Header) annotation;
// 检查参数类型是否为基本类型或字符串
if (Utils.hasUnresolvableType(type)) {
throw parameterError(method, p,
"@Header parameter type must not include a type variable or wildcard: %s", type);
}
// 创建 HeaderParameterHandler 实例
return new ParameterHandler.Header<>(header.value(),
converterFactory.stringConverter(type, annotations, retrofit));
} else if (annotation instanceof HeaderMap) {
// 如果注解是 HeaderMap 类型
if (!Map.class.isAssignableFrom(Utils.getRawType(type))) {
throw parameterError(method, p, "@HeaderMap parameter type must be Map.");
}
Type keyType = Utils.getSupertype(type, Map.class, String.class);
if (keyType != String.class) {
throw parameterError(method, p, "@HeaderMap keys must be of type String: %s", type);
}
Type valueType = Utils.getSupertype(type, Map.class, Object.class);
// 创建 HeaderMapParameterHandler 实例
return new ParameterHandler.HeaderMap<>(
converterFactory.stringConverter(valueType, annotations, retrofit));
} else if (annotation instanceof Body) {
// 如果注解是 Body 类型
if (isFormEncoded || isMultipart) {
throw parameterError(method, p,
"@Body parameters cannot be used with form or multi - part encoding.");
}
// 创建 BodyParameterHandler 实例
return new ParameterHandler.Body<>(
converterFactory.requestBodyConverter(type, annotations, methodAnnotations, retrofit));
} else if (annotation instanceof Field) {
// 如果注解是 Field 类型
if (!isFormEncoded) {
throw parameterError(method, p, "@Field parameters can only be used with form encoding.");
}
Field field = (Field) annotation;
// 检查参数类型是否为基本类型或字符串
if (Utils.hasUnresolvableType(type)) {
throw parameterError(method, p,
"@Field parameter type must not include a type variable or wildcard: %s", type);
}
// 创建 FieldParameterHandler 实例
return new ParameterHandler.Field<>(field.value(), field.encoded(),
converterFactory.stringConverter(type, annotations, retrofit));
} else if (annotation instanceof FieldMap) {
// 如果注解是 FieldMap 类型
if (!isFormEncoded) {
throw parameterError(method, p, "@FieldMap parameters can only be used with form encoding.");
}
if (!Map.class.isAssignableFrom(Utils.getRawType(type))) {
throw parameterError(method, p, "@FieldMap parameter type must be Map.");
}
Type keyType = Utils.getSupertype(type, Map.class, String.class);
if (keyType != String.class) {
throw parameterError(method, p, "@FieldMap keys must be of type String: %s", type);
}
Type valueType = Utils.getSupertype(type, Map.class, Object.class);
// 创建 FieldMapParameterHandler 实例
return new ParameterHandler.FieldMap<>(
converterFactory.stringConverter(valueType, annotations, retrofit));
} else if (annotation instanceof Part) {
// 如果注解是 Part 类型
if (!isMultipart) {
throw parameterError(method, p, "@Part parameters can only be used with multipart encoding.");
}
Part part = (Part) annotation;
String partName = part.value();
if (!"".equals(partName) && !partName.endsWith(";")) {
partName = partName + ";";
}
// 创建 PartParameterHandler 实例
return new ParameterHandler.Part<>(partName,
converterFactory.requestBodyConverter(type, annotations, methodAnnotations, retrofit));
} else if (annotation instanceof PartMap) {
// 如果注解是 PartMap 类型
if (!isMultipart) {
throw parameterError(method, p, "@PartMap parameters can only be used with multipart encoding.");
}
if (!Map.class.isAssignableFrom(Utils.getRawType(type))) {
throw parameterError(method, p, "@PartMap parameter type must be Map.");
}
Type keyType = Utils.getSupertype(type, Map.class, String.class);
if (keyType != String.class) {
throw parameterError(method, p, "@PartMap keys must be of type String: %s", type);
}
Type valueType = Utils.getSupertype(type, Map.class, Object.class);
// 创建 PartMapParameterHandler 实例
return new ParameterHandler.PartMap<>(
converterFactory.requestBodyConverter(valueType, annotations, methodAnnotations, retrofit));
}
return null;
}
}
@Path
注解解析:
Path
注解中获取占位符名称,检查该占位符是否存在于之前解析得到的 relativeUrlParamNames
列表中。如果不存在,会抛出异常,确保路径占位符的正确性。@Path
参数类型应该是基本类型或字符串。ParameterHandler.Path
实例,该实例负责处理路径占位符的替换。converterFactory.stringConverter
方法用于创建一个将参数类型转换为字符串的转换器,以便将参数值正确地替换到路径中。@Query
注解解析:
Query
注解,同样会检查参数类型是否包含不可解析的类型变量或通配符。ParameterHandler.Query
实例,该实例会将参数值作为查询参数添加到 URL 中。converterFactory.stringConverter
用于将参数值转换为字符串形式。@QueryMap
注解解析:
Map
类型,如果不是会抛出异常。Map
的键类型是否为 String
类型,若不是也会抛出异常。ParameterHandler.QueryMap
实例,该实例会将 Map
中的键值对作为查询参数添加到 URL 中。converterFactory.stringConverter
用于将 Map
的值转换为字符串。@Header
注解解析:
ParameterHandler.Header
实例,该实例会将参数值作为请求头添加到请求中。converterFactory.stringConverter
用于将参数值转换为字符串形式的请求头值。@HeaderMap
注解解析:
Map
类型,以及 Map
的键类型是否为 String
类型。ParameterHandler.HeaderMap
实例,该实例会将 Map
中的键值对作为请求头添加到请求中。converterFactory.stringConverter
用于将 Map
的值转换为字符串形式的请求头值。@Body
注解解析:
@Body
参数不能与表单或多部分编码同时使用。ParameterHandler.Body
实例,该实例会将参数作为请求体发送。converterFactory.requestBodyConverter
用于将参数类型转换为 RequestBody
类型,以便进行网络传输。@Field
注解解析:
@Field
参数只能用于表单编码请求。ParameterHandler.Field
实例,该实例会将参数值作为表单字段添加到请求体中。converterFactory.stringConverter
用于将参数值转换为字符串形式的表单字段值。@FieldMap
注解解析:
Map
类型,Map
的键类型是否为 String
类型。ParameterHandler.FieldMap
实例,该实例会将 Map
中的键值对作为表单字段添加到请求体中。converterFactory.stringConverter
用于将 Map
的值转换为字符串形式的表单字段值。@Part
注解解析:
@Part
参数只能用于多部分请求。Part
注解的 value
属性,确保其格式正确。ParameterHandler.Part
实例,该实例会将参数作为多部分请求的一部分添加到请求体中。converterFactory.requestBodyConverter
用于将参数类型转换为 RequestBody
类型。@PartMap
注解解析:
Map
类型,Map
的键类型是否为 String
类型。ParameterHandler.PartMap
实例,该实例会将 Map
中的键值对作为多部分请求的多个部分添加到请求体中。converterFactory.requestBodyConverter
用于将 Map
的值转换为 RequestBody
类型。RequestFactory
实例在完成所有参数注解的解析后,会调用 RequestFactory.Builder
的 build
方法来构建 RequestFactory
实例:
java
RequestFactory build() {
return new RequestFactory(this);
}
RequestFactory
类封装了所有解析得到的请求信息,包括请求方法、请求路径、请求头、请求体等,后续会根据这些信息创建实际的 Request
对象。
CallAdapter
和 Converter
实例在 ServiceMethod.parseAnnotations
方法中,还会创建 CallAdapter
和 Converter
实例:
java
// 创建 CallAdapter 实例,用于将 Call 对象转换为其他类型
CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method, returnType, requestFactory);
// 获取响应类型
Type responseType = callAdapter.responseType();
if (Utils.hasUnresolvableType(responseType)) {
throw methodError(method, "Call return type must not include a type variable or wildcard: %s", returnType);
}
// 创建 Converter 实例,用于将响应数据转换为指定类型
Converter<ResponseBody, T> responseConverter =
createResponseConverter(retrofit, method, responseType);
CallAdapter
实例创建createCallAdapter
方法通过 Retrofit
实例的 callAdapter
方法从 CallAdapter.Factory
列表中查找合适的 CallAdapter.Factory
,并调用其 get
方法创建 CallAdapter
实例。CallAdapter
的作用是将 Call
对象转换为其他类型,例如将 Call
转换为 Observable
等,以支持不同的异步编程模型。
Converter
实例创建createResponseConverter
方法通过 Retrofit
实例的 responseBodyConverter
方法从 Converter.Factory
列表中查找合适的 Converter.Factory
,并调用其 responseBodyConverter
方法创建 Converter
实例。Converter
的作用是将 ResponseBody
转换为指定的响应类型,例如将 JSON 数据转换为 Java 对象。
ServiceMethod
实例最后,根据前面解析得到的信息,创建 ServiceMethod
实例:
java
// 获取 OkHttpClient 实例
okhttp3.Call.Factory callFactory = retrofit.callFactory();
// 创建 ServiceMethod 实例
return new HttpServiceMethod<>(callFactory, requestFactory, callAdapter, responseConverter);
HttpServiceMethod
是 ServiceMethod
的具体实现类,它负责执行实际的 HTTP 请求,并处理响应结果。在 invoke
方法中,会根据 RequestFactory
创建 Request
对象,使用 OkHttpClient
发送请求,然后通过 CallAdapter
和 Converter
处理响应。
java
final class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
private final okhttp3.Call.Factory callFactory;
private final RequestFactory requestFactory;
private final CallAdapter<ResponseT, ReturnT> callAdapter;
private final Converter<ResponseBody, ResponseT> responseConverter;
HttpServiceMethod(okhttp3.Call.Factory callFactory, RequestFactory requestFactory,
CallAdapter<ResponseT, ReturnT> callAdapter,
Converter<ResponseBody, ResponseT> responseConverter) {
this.callFactory = callFactory;
this.requestFactory = requestFactory;
this.callAdapter = callAdapter;
this.responseConverter = responseConverter;
}
@Override
@Nullable ReturnT invoke(Object[] args) {
// 创建 OkHttp 的 Request 对象
Request request = requestFactory.create(args);
// 创建 OkHttp 的 Call 对象
okhttp3.Call call = callFactory.newCall(request);
// 调用 CallAdapter 的 adapt 方法将 Call 对象转换为指定类型
return callAdapter.adapt(new OkHttpCall<>(request, callFactory, responseConverter));
}
}
当 ServiceMethod
实例创建完成后,就可以使用它来发起 HTTP 请求了。在调用服务接口的方法时,实际上是调用 ServiceMethod
的 invoke
方法:
java
public interface ApiService {
@GET("users/{id}")
Call<User> getUser(@Path("id") int userId);
}
// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 创建服务代理对象
ApiService apiService = retrofit.create(ApiService.class);
// 发起请求
Call<User> call = apiService.getUser(1);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User user = response.body();
// 处理响应数据
} else {
// 处理请求失败
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// 处理请求异常
}
});
在上述代码中,apiService.getUser(1)
实际上调用了 ServiceMethod
的 invoke
方法,该方法会根据之前解析得到的注解信息创建 Request
对象,使用 OkHttpClient
发送请求,并通过 CallAdapter
和 Converter
处理响应结果。
Retrofit 的注解定义与解析模块是其核心功能之一,通过使用注解,开发者可以以一种简洁、声明式的方式定义 HTTP 请求。在解析过程中,Retrofit 利用 Java 的反射机制,在运行时获取方法和参数上的注解信息,并根据注解类型进行相应的处理。具体步骤包括解析请求方法和路径注解、解析参数注解、创建 RequestFactory
、CallAdapter
和 Converter
实例,最终创建 ServiceMethod
实例来执行实际的 HTTP 请求。这种设计使得 Retrofit 具有高度的灵活性和可扩展性,开发者可以通过自定义 CallAdapter.Factory
和 Converter.Factory
来满足不同的需求。同时,注解的使用也使得代码更加清晰、易读和易于维护,提高了开发效率。