Android Retrofit 请求执行模块执行原理深入源码分析(三)

一、引言

Retrofit 是 Square 公司开发的一款优秀的类型安全的 HTTP 客户端,在 Android 和 Java 开发中被广泛使用。它通过简洁的接口定义和强大的注解功能,使得开发者能够轻松地进行网络请求。请求执行模块是 Retrofit 的核心部分之一,负责将接口方法的调用转换为实际的 HTTP 请求,并处理响应结果。本文将深入 Retrofit 的源码,详细分析请求执行模块的执行原理。

二、Retrofit 基本使用回顾

在深入源码之前,我们先回顾一下 Retrofit 的基本使用。以下是一个简单的示例:

java

// 定义 API 接口
public interface GitHubService {@GET("users/{user}")Call<ResponseBody> getUser(@Path("user") String user);
}// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").build();// 创建 API 接口的代理对象
GitHubService service = retrofit.create(GitHubService.class);// 调用接口方法
Call<ResponseBody> call = service.getUser("octocat");// 执行同步请求
try {Response<ResponseBody> response = call.execute();if (response.isSuccessful()) {ResponseBody body = response.body();// 处理响应体}
} catch (IOException e) {e.printStackTrace();
}// 执行异步请求
call.enqueue(new Callback<ResponseBody>() {@Overridepublic void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {if (response.isSuccessful()) {ResponseBody body = response.body();// 处理响应体}}@Overridepublic void onFailure(Call<ResponseBody> call, Throwable t) {// 处理请求失败}
});

从上述代码可以看出,使用 Retrofit 进行网络请求主要包括以下几个步骤:

  1. 定义 API 接口,使用注解描述请求信息。

  2. 创建 Retrofit 实例,配置基础 URL 等信息。

  3. 创建 API 接口的代理对象。

  4. 调用接口方法,获取 Call 对象。

  5. 执行同步或异步请求,处理响应结果。

接下来,我们将逐步深入这些步骤背后的源码实现。

三、Retrofit 实例创建

3.1 Retrofit.Builder 类

Retrofit 实例的创建通常使用 Retrofit.Builder 类,该类提供了一系列的配置方法。以下是 Retrofit.Builder 类的部分源码:

java

public static final class Builder {// OkHttp 的请求工厂,用于创建实际的 HTTP 请求private okhttp3.Call.Factory callFactory;// 基础 URLprivate HttpUrl baseUrl;// 调用适配器工厂列表,用于将网络请求结果适配为不同的类型private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();// 转换器工厂列表,用于将请求参数和响应结果进行序列化和反序列化private final List<Converter.Factory> converterFactories = new ArrayList<>();// 回调执行器,用于将回调切换到指定线程private Executor callbackExecutor;// 是否验证服务接口private boolean validateEagerly;public Builder() {// 默认使用 OkHttpClient 作为请求工厂this(Platform.get());}Builder(Platform platform) {// 添加默认的调用适配器工厂callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));}// 设置请求工厂public Builder callFactory(okhttp3.Call.Factory factory) {this.callFactory = checkNotNull(factory, "factory == null");return this;}// 设置基础 URLpublic Builder baseUrl(String baseUrl) {checkNotNull(baseUrl, "baseUrl == null");return baseUrl(HttpUrl.get(baseUrl));}public Builder baseUrl(HttpUrl baseUrl) {checkNotNull(baseUrl, "baseUrl == null");List<String> pathSegments = baseUrl.pathSegments();if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);}this.baseUrl = baseUrl;return this;}// 添加调用适配器工厂public Builder addCallAdapterFactory(CallAdapter.Factory factory) {callAdapterFactories.add(checkNotNull(factory, "factory == null"));return this;}// 添加转换器工厂public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(checkNotNull(factory, "factory == null"));return this;}// 设置回调执行器public Builder callbackExecutor(Executor executor) {this.callbackExecutor = checkNotNull(executor, "executor == null");return this;}// 是否验证服务接口public Builder validateEagerly(boolean validateEagerly) {this.validateEagerly = validateEagerly;return this;}// 构建 Retrofit 实例public Retrofit build() {if (baseUrl == null) {throw new IllegalStateException("Base URL required.");}okhttp3.Call.Factory callFactory = this.callFactory;if (callFactory == null) {// 如果没有设置请求工厂,使用默认的 OkHttpClientcallFactory = new OkHttpClient();}Executor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {// 如果没有设置回调执行器,使用平台默认的执行器callbackExecutor = Platform.get().defaultCallbackExecutor();}// 复制调用适配器工厂列表,并添加默认的调用适配器工厂List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);callAdapterFactories.addAll(Platform.get().defaultCallAdapterFactories(callbackExecutor));// 复制转换器工厂列表,并添加默认的转换器工厂List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);converterFactories.add(0, new BuiltInConverters());return new Retrofit(callFactory, baseUrl, converterFactories, callAdapterFactories,callbackExecutor, validateEagerly);}
}

Retrofit.Builder 类的主要作用是配置 Retrofit 实例的各种参数,包括请求工厂、基础 URL、调用适配器工厂、转换器工厂和回调执行器等。在 build() 方法中,会对这些参数进行检查和默认值的设置,最终创建一个 Retrofit 实例。

3.2 Retrofit 类

Retrofit 类是 Retrofit 框架的核心类,它封装了各种配置信息,并提供了创建接口代理对象的方法。以下是 Retrofit 类的部分源码:

java

public final class Retrofit {// OkHttp 的请求工厂private final okhttp3.Call.Factory callFactory;// 基础 URLprivate final HttpUrl baseUrl;// 转换器工厂列表private final List<Converter.Factory> converterFactories;// 调用适配器工厂列表private final List<CallAdapter.Factory> callAdapterFactories;// 回调执行器private final Executor callbackExecutor;// 服务方法缓存private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();// 是否验证服务接口private final boolean validateEagerly;Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,Executor callbackExecutor, boolean validateEagerly) {this.callFactory = callFactory;this.baseUrl = baseUrl;this.converterFactories = unmodifiableList(converterFactories);this.callAdapterFactories = unmodifiableList(callAdapterFactories);this.callbackExecutor = callbackExecutor;this.validateEagerly = validateEagerly;if (validateEagerly) {// 如果需要验证服务接口,遍历所有方法并加载服务方法eagerlyValidateMethods();}}// 获取请求工厂public okhttp3.Call.Factory callFactory() {return callFactory;}// 获取基础 URLpublic HttpUrl baseUrl() {return baseUrl;}// 获取转换器工厂列表public List<Converter.Factory> converterFactories() {return converterFactories;}// 获取调用适配器工厂列表public List<CallAdapter.Factory> callAdapterFactories() {return callAdapterFactories;}// 获取回调执行器public Executor callbackExecutor() {return callbackExecutor;}// 创建 API 接口的代理对象public <T> T create(final Class<T> service) {// 验证传入的 service 是否为接口类型validateServiceInterface(service);// 使用动态代理创建代理对象return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},new InvocationHandler() {private final Platform platform = Platform.get();@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 如果调用的是 Object 类的方法,直接调用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}// 如果是默认方法,根据平台进行处理if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}// 创建 ServiceMethod 对象ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);// 创建 OkHttpCall 对象OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);// 通过 CallAdapter 进行适配return serviceMethod.callAdapter.adapt(okHttpCall);}});}// 加载服务方法ServiceMethod<?, ?> loadServiceMethod(Method method) {// 从缓存中获取 ServiceMethod 对象ServiceMethod<?, ?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {// 再次从缓存中获取 ServiceMethod 对象result = serviceMethodCache.get(method);if (result == null) {// 如果缓存中没有,则创建一个新的 ServiceMethod 对象result = ServiceMethod.parseAnnotations(this, method);// 将新创建的 ServiceMethod 对象放入缓存中serviceMethodCache.put(method, result);}}return result;}// 提前验证服务接口的方法private void eagerlyValidateMethods() {Platform platform = Platform.get();for (Method method : getClass().getDeclaredMethods()) {if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {loadServiceMethod(method);}}}
}

Retrofit 类的主要作用是封装配置信息,并提供 create() 方法用于创建 API 接口的代理对象。在 create() 方法中,会使用 Java 的动态代理机制创建一个实现了指定 API 接口的代理对象,并在 InvocationHandlerinvoke() 方法中处理接口方法的调用。

四、接口代理对象的创建

4.1 create() 方法

create() 方法是创建接口代理对象的核心方法,以下是该方法的详细分析:

java

public <T> T create(final Class<T> service) {// 验证传入的 service 是否为接口类型validateServiceInterface(service);// 使用动态代理创建代理对象return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},new InvocationHandler() {private final Platform platform = Platform.get();@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 如果调用的是 Object 类的方法,直接调用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}// 如果是默认方法,根据平台进行处理if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}// 创建 ServiceMethod 对象ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);// 创建 OkHttpCall 对象OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);// 通过 CallAdapter 进行适配return serviceMethod.callAdapter.adapt(okHttpCall);}});
}

create() 方法的主要步骤如下:

  1. 验证接口类型:调用 validateServiceInterface() 方法验证传入的 service 是否为接口类型。

java

private void validateServiceInterface(Class<?> service) {// 检查传入的 service 是否为接口类型if (!service.isInterface()) {throw new IllegalArgumentException("API declarations must be interfaces.");}// 检查接口是否有默认方法,并且平台是否支持默认方法if (Platform.get().isDefaultMethodProblematic()) {for (Method method : service.getDeclaredMethods()) {if (Platform.get().isDefaultMethod(method)) {throw new IllegalArgumentException("@SkipCallbackExecutor annotation is required on methods "+ "with default implementations when targeting API 24 and lower due "+ "to an issue with default method dispatch.");}}}
}
  1. 使用动态代理创建代理对象:使用 Java 的动态代理机制创建一个实现了指定 API 接口的代理对象。

  2. 实现 InvocationHandler 接口:在 invoke() 方法中处理接口方法的调用。

    • 如果调用的是 Object 类的方法,直接调用该方法。

    • 如果是接口的默认方法,根据平台进行处理。

    • 调用 loadServiceMethod() 方法创建 ServiceMethod 对象。

java

ServiceMethod<?, ?> loadServiceMethod(Method method) {// 从缓存中获取 ServiceMethod 对象ServiceMethod<?, ?> result = serviceMethodCache.get(method);if (result != null) return result;synchronized (serviceMethodCache) {// 再次从缓存中获取 ServiceMethod 对象result = serviceMethodCache.get(method);if (result == null) {// 如果缓存中没有,则创建一个新的 ServiceMethod 对象result = ServiceMethod.parseAnnotations(this, method);// 将新创建的 ServiceMethod 对象放入缓存中serviceMethodCache.put(method, result);}}return result;
}
  • 使用 ServiceMethod 对象和方法参数创建 OkHttpCall 对象。
  • 调用 serviceMethod.callAdapter.adapt() 方法对 OkHttpCall 对象进行适配。

4.2 ServiceMethod.parseAnnotations() 方法

ServiceMethod.parseAnnotations() 方法用于解析 API 接口方法的注解,创建 ServiceMethod 对象。以下是该方法的详细源码和分析:

java

static <T, R> ServiceMethod<T, R> parseAnnotations(Retrofit retrofit, Method method) {// 创建 RequestFactory 对象,用于解析请求相关的注解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.");}// 获取 CallAdapter 对象,用于适配网络请求的结果CallAdapter<T, R> callAdapter = createCallAdapter(retrofit, method, returnType);// 获取响应类型Type responseType = callAdapter.responseType();if (Utils.hasUnresolvableType(responseType)) {throw methodError(method, "Call adapter returned a type that contains wildcards: %s",responseType);}// 获取 Converter 对象,用于将响应结果进行反序列化Converter<ResponseBody, T> responseConverter =createResponseConverter(retrofit, method, responseType);// 获取 OkHttp 的请求工厂okhttp3.Call.Factory callFactory = retrofit.callFactory;return new ServiceMethod<>(requestFactory, callAdapter, responseConverter, callFactory);
}// 创建 CallAdapter 对象
private static <T, R> CallAdapter<T, R> createCallAdapter(Retrofit retrofit, Method method, Type returnType) {Annotation[] annotations = method.getAnnotations();try {// 遍历调用适配器工厂列表,查找合适的 CallAdapter 工厂for (CallAdapter.Factory factory : retrofit.callAdapterFactories()) {CallAdapter<?, ?> adapter = factory.get(returnType, annotations, retrofit);if (adapter != null) {// 找到合适的 CallAdapter 工厂,返回其创建的 CallAdapter 对象return (CallAdapter<T, R>) adapter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create call adapter for %s", returnType);}throw methodError(method, "Could not locate call adapter for %s.", returnType);
}// 创建响应转换器对象
private static <T> Converter<ResponseBody, T> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {Annotation[] annotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的 Converter 工厂for (Converter.Factory factory : retrofit.converterFactories()) {Converter<ResponseBody, ?> converter = factory.responseBodyConverter(responseType, annotations, retrofit);if (converter != null) {// 找到合适的 Converter 工厂,返回其创建的 Converter 对象return (Converter<ResponseBody, T>) converter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create converter for %s", responseType);}throw methodError(method, "Could not locate response converter for %s.", responseType);
}

ServiceMethod.parseAnnotations() 方法的主要步骤如下:

  1. 创建 RequestFactory 对象:调用 RequestFactory.parseAnnotations() 方法解析请求相关的注解,创建 RequestFactory 对象。

java

static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {// 创建 RequestFactory.Builder 对象return new Builder(retrofit, method).build();
}// RequestFactory.Builder 类
static final class Builder {private final Retrofit retrofit;private final Method method;private final Annotation[] methodAnnotations;private final Annotation[][] parameterAnnotationsArray;private final Type[] parameterTypes;private HttpUrl baseUrl;private String httpMethod;private boolean hasBody;private boolean isFormEncoded;private boolean isMultipart;private String relativeUrl;private ParameterHandler<?>[] parameterHandlers;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.).");}// 解析参数注解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(method, p, "Parameter type must not include a type variable or wildcard: %s",parameterType);}Annotation[] parameterAnnotations = parameterAnnotationsArray[p];if (parameterAnnotations == null) {throw parameterError(method, p, "No Retrofit annotation found.");}parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);}if (relativeUrl == null && !hasBody) {throw methodError(method, "Non-body HTTP method cannot contain @Body.");}if (isFormEncoded && isMultipart) {throw methodError(method, "Only one encoding annotation is allowed.");}return new RequestFactory(this);}private void parseMethodAnnotation(Annotation annotation) {if (annotation instanceof GET) {parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);} 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 DELETE) {parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);} else if (annotation instanceof HEAD) {parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);if (hasBody) {throw methodError(method, "@HEAD method must not have a request body.");}} else if (annotation instanceof PATCH) {parseHttpMethodAndPath("PATCH", ((PATCH) 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;}}private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {if (this.httpMethod != null) {throw methodError(method, "Only one HTTP method is allowed. Found: %s and %s.",this.httpMethod, httpMethod);}this.httpMethod = httpMethod;this.hasBody = hasBody;if (value.isEmpty()) {return;}// Get the relative URL path and existing query string, if present.int question = value.indexOf('?');if (question != -1 && question < value.length() - 1) {// Ensure the query string does not have any named parameters.String queryParams = value.substring(question + 1);Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);if (queryParamMatcher.find()) {throw methodError(method, "URL query string "%s" must not have replace block. "+ "For dynamic query parameters use @Query.", queryParams);}}this.relativeUrl = value;this.relativeUrlParamNames = parsePathParameters(value);}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) 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.");}return result;}private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) {if (annotation instanceof retrofit2.http.Path) {retrofit2.http.Path path = (retrofit2.http.Path) annotation;String name = path.value();validatePathName(p, name);// 创建 Path 类型的 ParameterHandler,用于处理路径参数return new ParameterHandler.Path<>(name,retrofit.stringConverter(type, annotations));} else if (annotation instanceof retrofit2.http.Query) {retrofit2.http.Query query = (retrofit2.http.Query) annotation;String name = query.value();// 创建 Query 类型的 ParameterHandler,用于处理查询参数return new ParameterHandler.Query<>(name,retrofit.stringConverter(type, annotations), query.encoded());} else if (annotation instanceof retrofit2.http.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.");}Type valueType = Utils.getSupertype(type, Map.class, Object

四、接口代理对象的创建

4.2 ServiceMethod.parseAnnotations() 方法

4.2.1 parseParameterAnnotation 方法详细解析

java

        } else if (annotation instanceof retrofit2.http.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.");}Type valueType = Utils.getSupertype(type, Map.class, Object.class);// 创建 QueryMap 类型的 ParameterHandler,用于处理查询参数映射return new ParameterHandler.QueryMap<>(retrofit.stringConverter(valueType, annotations),((retrofit2.http.QueryMap) annotation).encoded());} else if (annotation instanceof retrofit2.http.Header) {retrofit2.http.Header header = (retrofit2.http.Header) annotation;String name = header.value();// 创建 Header 类型的 ParameterHandler,用于处理请求头参数return new ParameterHandler.Header<>(name,retrofit.stringConverter(type, annotations));} else if (annotation instanceof retrofit2.http.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.");}Type valueType = Utils.getSupertype(type, Map.class, Object.class);// 创建 HeaderMap 类型的 ParameterHandler,用于处理请求头参数映射return new ParameterHandler.HeaderMap<>(retrofit.stringConverter(valueType, annotations));} else if (annotation instanceof retrofit2.http.Field) {if (!isFormEncoded) {throw parameterError(method, p, "@Field parameters can only be used with form encoding.");}retrofit2.http.Field field = (retrofit2.http.Field) annotation;String name = field.value();// 创建 Field 类型的 ParameterHandler,用于处理表单字段参数return new ParameterHandler.Field<>(name,retrofit.stringConverter(type, annotations), field.encoded());} else if (annotation instanceof retrofit2.http.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.");}Type valueType = Utils.getSupertype(type, Map.class, Object.class);// 创建 FieldMap 类型的 ParameterHandler,用于处理表单字段参数映射return new ParameterHandler.FieldMap<>(retrofit.stringConverter(valueType, annotations),((retrofit2.http.FieldMap) annotation).encoded());} else if (annotation instanceof retrofit2.http.Part) {if (!isMultipart) {throw parameterError(method, p, "@Part parameters can only be used with multipart encoding.");}retrofit2.http.Part part = (retrofit2.http.Part) annotation;String name = part.value();if (name.isEmpty()) {return new ParameterHandler.Part<>();}MediaType mediaType = null;if (!"*/*".equals(name)) {try {mediaType = MediaType.get(name);} catch (IllegalArgumentException e) {throw parameterError(method, p, "Malformed media type: %s", name);}}// 创建 Part 类型的 ParameterHandler,用于处理多部分请求的部分数据return new ParameterHandler.Part<>(name, mediaType,retrofit.stringConverter(type, annotations));} else if (annotation instanceof retrofit2.http.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.");}Type valueType = Utils.getSupertype(type, Map.class, Object.class);// 创建 PartMap 类型的 ParameterHandler,用于处理多部分请求的部分数据映射return new ParameterHandler.PartMap<>(retrofit.stringConverter(valueType, annotations));} else if (annotation instanceof retrofit2.http.Body) {if (hasBody) {// 创建 Body 类型的 ParameterHandler,用于处理请求体return new ParameterHandler.Body<>(retrofit.requestBodyConverter(type, annotations, methodAnnotations));}throw parameterError(method, p, "@Body parameters cannot be used with HTTP methods "+ "that do not have a request body (e.g., GET, HEAD).");} else if (annotation instanceof retrofit2.http.Tag) {// 创建 Tag 类型的 ParameterHandler,用于设置请求标签return new ParameterHandler.Tag<>(type);}return null;}

parseParameterAnnotation 方法会根据不同的注解类型创建相应的 ParameterHandler 对象。这些 ParameterHandler 对象负责处理接口方法参数在请求中的不同使用方式,例如将参数作为路径参数、查询参数、请求头参数、表单字段参数、多部分请求数据等。

4.2.2 build 方法总结

java

    RequestFactory build() {// 解析方法注解for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}if (httpMethod == null) {throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");}// 解析参数注解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(method, p, "Parameter type must not include a type variable or wildcard: %s",parameterType);}Annotation[] parameterAnnotations = parameterAnnotationsArray[p];if (parameterAnnotations == null) {throw parameterError(method, p, "No Retrofit annotation found.");}parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);}if (relativeUrl == null && !hasBody) {throw methodError(method, "Non-body HTTP method cannot contain @Body.");}if (isFormEncoded && isMultipart) {throw methodError(method, "Only one encoding annotation is allowed.");}return new RequestFactory(this);}

build 方法首先遍历方法注解,确定 HTTP 请求方法、相对 URL、是否有请求体、是否为表单编码或多部分编码等信息。然后遍历参数注解,为每个参数创建对应的 ParameterHandler 对象。最后进行一些合法性检查,确保请求配置的正确性,最终创建并返回 RequestFactory 对象。

4.3 createCallAdapter 方法和 createResponseConverter 方法

4.3.1 createCallAdapter 方法

java

private static <T, R> CallAdapter<T, R> createCallAdapter(Retrofit retrofit, Method method, Type returnType) {Annotation[] annotations = method.getAnnotations();try {// 遍历调用适配器工厂列表,查找合适的 CallAdapter 工厂for (CallAdapter.Factory factory : retrofit.callAdapterFactories()) {CallAdapter<?, ?> adapter = factory.get(returnType, annotations, retrofit);if (adapter != null) {// 找到合适的 CallAdapter 工厂,返回其创建的 CallAdapter 对象return (CallAdapter<T, R>) adapter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create call adapter for %s", returnType);}throw methodError(method, "Could not locate call adapter for %s.", returnType);
}

createCallAdapter 方法会遍历 retrofit 中的 callAdapterFactories 列表,依次调用每个工厂的 get 方法,传入方法的返回类型、注解和 retrofit 实例,尝试找到一个能够处理该返回类型的 CallAdapter 工厂。如果找到,则返回该工厂创建的 CallAdapter 对象;如果遍历完所有工厂都没有找到合适的,则抛出异常。

4.3.2 createResponseConverter 方法

java

private static <T> Converter<ResponseBody, T> createResponseConverter(Retrofit retrofit, Method method, Type responseType) {Annotation[] annotations = method.getAnnotations();try {// 遍历转换器工厂列表,查找合适的 Converter 工厂for (Converter.Factory factory : retrofit.converterFactories()) {Converter<ResponseBody, ?> converter = factory.responseBodyConverter(responseType, annotations, retrofit);if (converter != null) {// 找到合适的 Converter 工厂,返回其创建的 Converter 对象return (Converter<ResponseBody, T>) converter;}}} catch (RuntimeException e) {throw methodError(method, e, "Unable to create converter for %s", responseType);}throw methodError(method, "Could not locate response converter for %s.", responseType);
}

createResponseConverter 方法与 createCallAdapter 方法类似,它会遍历 retrofit 中的 converterFactories 列表,依次调用每个工厂的 responseBodyConverter 方法,传入响应类型、注解和 retrofit 实例,尝试找到一个能够处理该响应类型的 Converter 工厂。如果找到,则返回该工厂创建的 Converter 对象;如果遍历完所有工厂都没有找到合适的,则抛出异常。

五、接口方法调用与 OkHttpCall

5.1 InvocationHandler.invoke 方法回顾

java

@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// 如果调用的是 Object 类的方法,直接调用if (method.getDeclaringClass() == Object.class) {return method.invoke(this, args);}// 如果是默认方法,根据平台进行处理if (platform.isDefaultMethod(method)) {return platform.invokeDefaultMethod(method, service, proxy, args);}// 创建 ServiceMethod 对象ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);// 创建 OkHttpCall 对象OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);// 通过 CallAdapter 进行适配return serviceMethod.callAdapter.adapt(okHttpCall);
}

当调用接口方法时,会触发 InvocationHandlerinvoke 方法。该方法会先判断调用的是否为 Object 类的方法或接口的默认方法,如果是则直接处理。否则,会加载 ServiceMethod 对象,使用该对象和方法参数创建 OkHttpCall 对象,最后通过 CallAdapterOkHttpCall 对象进行适配并返回适配后的对象。

5.2 OkHttpCall

5.2.1 类的基本结构和成员变量

java

final class OkHttpCall<T> implements Call<T> {private final ServiceMethod<T, ?> serviceMethod;private final Object[] args;private volatile boolean canceled;private @Nullable okhttp3.Call rawCall;private @Nullable Throwable creationFailure;private boolean executed;OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {this.serviceMethod = serviceMethod;this.args = args;}// ...其他方法
}

OkHttpCall 类实现了 Call 接口,封装了 ServiceMethod 和方法参数。rawCall 是 OkHttp 的 Call 对象,用于实际执行 HTTP 请求。executed 标志该请求是否已经执行过,canceled 标志请求是否被取消。

5.2.2 request 方法

java

@Override
public synchronized Request request() {okhttp3.Call call = rawCall;if (call != null) {return call.request();}if (creationFailure != null) {if (creationFailure instanceof IOException) {throw new RuntimeException("Unable to create request.", creationFailure);} else {throw (RuntimeException) creationFailure;}}try {// 创建 OkHttp 的 Request 对象rawCall = call = serviceMethod.toCall(args);return call.request();} catch (RuntimeException | Error e) {creationFailure = e;throw e;}
}

request 方法用于获取实际的 OkHttp 请求对象。如果 rawCall 已经创建,则直接返回其请求对象。如果创建请求时出现异常,会抛出相应的异常。否则,调用 serviceMethod.toCall(args) 方法创建 rawCall 并返回其请求对象。

5.2.3 enqueue 方法

java

@Override
public void enqueue(final Callback<T> callback) {checkNotNull(callback, "callback == null");okhttp3.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 的 Call 对象rawCall = call = serviceMethod.toCall(args);} catch (Throwable t) {failure = creationFailure = t;}}}if (failure != null) {// 处理创建请求时的异常callback.onFailure(this, failure);return;}if (canceled) {call.cancel();}// 执行请求并处理响应call.enqueue(new okhttp3.Callback() {@Overridepublic void onFailure(okhttp3.Call call, IOException e) {// 切换到主线程回调失败结果callbackOnMain(e);}@Overridepublic void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {Response<T> response;try {// 解析响应结果response = parseResponse(rawResponse);} catch (Throwable e) {// 处理解析响应时的异常callbackOnMain(e);return;}// 切换到主线程回调成功结果callbackOnMain(response);}});
}// 切换到主线程回调的辅助方法
private void callbackOnMain(final Throwable t) {// 获取主线程的执行器executorService.execute(new Runnable() {@Overridepublic void run() {callback.onFailure(OkHttpCall.this, t);}});
}private void callbackOnMain(final Response<T> response) {executorService.execute(new Runnable() {@Overridepublic void run() {if (response.isSuccessful()) {callback.onResponse(OkHttpCall.this, response);} else {callback.onFailure(OkHttpCall.this, new IOException("HTTP " + response.code()));}}});
}

enqueue 方法用于异步执行请求。首先进行同步控制,确保请求只执行一次。然后创建 rawCall 对象,如果创建过程中出现异常,直接回调失败结果。接着判断请求是否被取消,若取消则取消 rawCall。最后使用 rawCallenqueue 方法异步执行请求,并在回调中处理响应结果。callbackOnMain 方法用于将回调切换到主线程。

5.2.4 parseResponse 方法

java

private Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody = rawResponse.body();// 解析响应头Headers headers = Headers.of(rawResponse.headers());if (!rawResponse.isSuccessful()) {// 处理非成功响应rawBody.close();return Response.error(parseErrorBodyIfPossible(rawResponse), headers);}if (rawBody == null) {// 处理空响应体return Response.success(null, headers);}// 解析响应体T body = serviceMethod.toResponse(rawBody);return Response.success(body, headers);
}// 解析错误响应体
private IOException parseErrorBodyIfPossible(okhttp3.Response rawResponse) {try {return serviceMethod.parseError(rawResponse);} catch (RuntimeException e) {return e;} catch (IOException e) {return e;} catch (Throwable t) {return new RuntimeException(t);}
}

parseResponse 方法用于解析 OkHttp 的响应结果。如果响应状态码不是 2xx,会处理错误响应。如果响应体为空,返回成功但 bodynull 的响应。否则,调用 serviceMethod.toResponse(rawBody) 方法解析响应体并返回成功响应。

5.3 ServiceMethod.toCall 方法

java

okhttp3.Call toCall(Object... args) {// 创建 OkHttp 的 Request 对象Request request = requestFactory.create(args);// 使用 OkHttp 的 Call.Factory 创建 Call 对象return callFactory.newCall(request);
}

toCall 方法调用 requestFactory.create(args) 方法创建 OkHttp 的 Request 对象,然后使用 callFactory 创建 Call 对象,用于实际执行 HTTP 请求。

5.4 RequestFactory.create 方法

java

Request create(Object... args) {// 解析请求 URLHttpUrl baseUrl = this.baseUrl;String relativeUrl = this.relativeUrl;HttpUrl.Builder urlBuilder = baseUrl.newBuilder(relativeUrl);if (urlBuilder == null) {throw new IllegalArgumentException("Malformed URL.");}// 解析请求参数ParameterHandler<?>[] parameterHandlers = this.parameterHandlers;Headers.Builder headersBuilder = new Headers.Builder();RequestBody body = null;for (int i = 0; i < parameterHandlers.length; i++) {parameterHandlers[i].apply(args[i], urlBuilder, headersBuilder, bodyBuilder);}// 创建 OkHttp 的 Request 对象return new Request.Builder().url(urlBuilder.build()).headers(headersBuilder.build()).method(httpMethod, bodyBuilder.build()).build();
}

create 方法根据 baseUrlrelativeUrl 构建请求 URL。然后遍历 parameterHandlers 数组,将方法参数应用到请求的 URL、请求头和请求体中。最后使用 Request.Builder 创建 OkHttp 的 Request 对象。

六、CallAdapter 的适配过程

6.1 CallAdapter 接口和工厂类

java

public interface CallAdapter<R, T> {// 获取响应类型Type responseType();// 适配 Call 对象T adapt(Call<R> call);// 工厂类,用于创建 CallAdapter 对象abstract class Factory {// 根据返回类型和注解创建 CallAdapter 对象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);}}
}

CallAdapter 接口定义了两个方法,responseType 用于获取响应类型,adapt 用于适配 Call 对象。Factory 是一个抽象类,用于创建 CallAdapter 对象。

6.2 ExecutorCallAdapterFactoryExecutorCallAdapter

java

public final class ExecutorCallAdapterFactory extends CallAdapter.Factory {final Executor callbackExecutor;public ExecutorCallAdapterFactory(Executor callbackExecutor) {this.callbackExecutor = callbackExecutor;}@Overridepublic @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,Retrofit retrofit) {if (getRawType(returnType) != Call.class) {return null;}final Type responseType = Utils.getCallResponseType(returnType);return new ExecutorCallAdapter<>(callbackExecutor, responseType);}
}final class ExecutorCallAdapter<T, R> implements CallAdapter<T, R> {private final Executor callbackExecutor;private final Type responseType;ExecutorCallAdapter(Executor callbackExecutor, Type responseType) {this.callbackExecutor = callbackExecutor;this.responseType = responseType;}@Overridepublic Type responseType() {return responseType;}@Overridepublic R adapt(Call<T> call) {// 创建适配后的 Call 对象return (R) new ExecutorCallbackCall<>(callbackExecutor, call);}
}final class ExecutorCallbackCall<T> implements Call<T> {private final Executor callbackExecutor;private final Call<T> delegate;ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {this.callbackExecutor = callbackExecutor;this.delegate = delegate;}@Overridepublic void enqueue(final Callback<T> callback) {// 检查回调是否为 nullcheckNotNull(callback, "callback == null");// 执行原始请求,并在回调时切换线程delegate.enqueue(new Callback<T>() {@Overridepublic void onResponse(Call<T> call, final Response<T> response) {// 切换到指定线程回调callbackExecutor.execute(new Runnable() {@Overridepublic void run() {if (delegate.isCanceled()) {callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));} else {callback.onResponse(ExecutorCallbackCall.this, response);}}});}@Overridepublic void onFailure(Call<T> call, final Throwable t) {// 切换到指定线程回调callbackExecutor.execute(new Runnable() {@Overridepublic void run() {callback.onFailure(ExecutorCallbackCall.this, t);}});}});}// 其他方法直接委托给原始 Call 对象@Overridepublic Response<T> execute() throws IOException {return delegate.execute();}@Overridepublic boolean isExecuted() {return delegate.isExecuted();}@Overridepublic void cancel() {delegate.cancel();}@Overridepublic boolean isCanceled() {return delegate.isCanceled();}@Overridepublic Call<T> clone() {return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());}@Overridepublic Request request() {return delegate.request();}
}

ExecutorCallAdapterFactory 是默认的 CallAdapter 工厂类,它会根据返回类型判断是否为 Call 类型,如果是则创建 ExecutorCallAdapter 对象。ExecutorCallAdapteradapt 方法会创建 ExecutorCallbackCall 对象,该对象会将回调切换到指定的线程。

七、Converter 的转换过程

7.1 Converter 接口和工厂类

java

public interface Converter<F, T> {// 转换方法T convert(F value) throws IOException;// 工厂类,用于创建 Converter 对象abstract class Factory {// 创建请求体转换器public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return null;}// 创建响应体转换器public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,Annotation[] annotations, Retrofit retrofit) {return null;}// 创建字符串转换器public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,Retrofit retrofit) {return null;}}
}

Converter 接口定义了 convert 方法,用于进行数据转换。Factory 是一个抽象类,提供了创建请求体转换器、响应体转换器和字符串转换器的方法。

7.2 GsonConverterFactory 和相关转换器

java

public final class GsonConverterFactory extends Converter.Factory {private final Gson gson;private GsonConverterFactory(Gson gson) {this.gson = gson;}public static GsonConverterFactory create() {return create(new Gson());}public static GsonConverterFactory create(Gson gson) {return new GsonConverterFactory(gson);}@Overridepublic Converter<ResponseBody, ?> responseBody

7.2 GsonConverterFactory 和相关转换器

java

    @Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {return new GsonResponseBodyConverter<>(gson, type);}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {return new GsonRequestBodyConverter<>(gson, type);}
}final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final Gson gson;private final TypeAdapter<T> adapter;GsonResponseBodyConverter(Gson gson, Type type) {this.gson = gson;// 通过 Gson 获取指定类型的 TypeAdapter,用于解析 JSON 数据this.adapter = gson.getAdapter(TypeToken.get(type));}@Overridepublic T convert(ResponseBody value) throws IOException {// 创建 JsonReader 对象,用于读取响应体的字符流JsonReader jsonReader = gson.newJsonReader(value.charStream());try {// 使用 TypeAdapter 从 JsonReader 中读取数据并转换为指定类型return adapter.read(jsonReader);} finally {// 关闭响应体value.close();}}
}final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");private static final Charset UTF_8 = Charset.forName("UTF-8");private final Gson gson;private final TypeAdapter<T> adapter;GsonRequestBodyConverter(Gson gson, Type type) {this.gson = gson;// 通过 Gson 获取指定类型的 TypeAdapter,用于将对象转换为 JSON 数据this.adapter = gson.getAdapter(TypeToken.get(type));}@Overridepublic RequestBody convert(T value) throws IOException {// 创建 ByteArrayOutputStream 用于存储序列化后的 JSON 数据ByteArrayOutputStream out = new ByteArrayOutputStream();// 创建 JsonWriter 对象,用于将对象以 JSON 格式写入输出流JsonWriter jsonWriter = gson.newJsonWriter(new OutputStreamWriter(out, UTF_8));try {// 使用 TypeAdapter 将对象写入 JsonWriteradapter.write(jsonWriter, value);// 刷新 JsonWriter 以确保所有数据都被写入输出流jsonWriter.close();} catch (IOException e) {// 捕获可能的 I/O 异常并重新抛出throw new AssertionError(e); // Writing to a buffer can't throw an IOException.}// 创建 OkHttp 的 RequestBody 对象,指定媒体类型和字节数组return RequestBody.create(MEDIA_TYPE, out.toByteArray());}
}
7.2.1 GsonConverterFactory 分析

GsonConverterFactory 是一个实现了 Converter.Factory 接口的工厂类,它的主要作用是创建 Gson 相关的请求体转换器和响应体转换器。通过调用 create 方法可以传入自定义的 Gson 实例,如果不传入则使用默认的 Gson 实例。

7.2.2 GsonResponseBodyConverter 分析
  • 构造函数:接收 Gson 实例和目标类型 type,通过 GsongetAdapter 方法获取对应的 TypeAdapter,这个 TypeAdapterGson 用于序列化和反序列化对象的核心工具。
  • convert 方法:将 ResponseBody 转换为目标类型 T。首先创建 JsonReader 用于读取响应体的字符流,然后使用 TypeAdapterJsonReader 中读取数据并转换为目标类型,最后关闭响应体。
7.2.3 GsonRequestBodyConverter 分析
  • 构造函数:同样接收 Gson 实例和目标类型 type,获取对应的 TypeAdapter
  • convert 方法:将目标类型 T 的对象转换为 RequestBody。创建 ByteArrayOutputStream 用于存储序列化后的 JSON 数据,再创建 JsonWriter 将对象以 JSON 格式写入输出流,最后使用 RequestBody.create 方法创建 RequestBody 对象。

7.3 其他常见的 Converter 工厂

7.3.1 ScalarsConverterFactory

java

public final class ScalarsConverterFactory extends Converter.Factory {private static final MediaType MEDIA_TYPE = MediaType.get("text/plain; charset=UTF-8");@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {if (type == String.class) {return new StringResponseBodyConverter();}if (type == ByteString.class) {return new ByteStringResponseBodyConverter();}if (type == byte[].class) {return new ByteArrayResponseBodyConverter();}return null;}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {if (type == String.class) {return new StringRequestBodyConverter();}if (type == ByteString.class) {return new ByteStringRequestBodyConverter();}if (type == byte[].class) {return new ByteArrayRequestBodyConverter();}return null;}static final class StringResponseBodyConverter implements Converter<ResponseBody, String> {@Overridepublic String convert(ResponseBody value) throws IOException {try {return value.string();} finally {value.close();}}}static final class ByteStringResponseBodyConverter implements Converter<ResponseBody, ByteString> {@Overridepublic ByteString convert(ResponseBody value) throws IOException {try {return value.source().readByteString();} finally {value.close();}}}static final class ByteArrayResponseBodyConverter implements Converter<ResponseBody, byte[]> {@Overridepublic byte[] convert(ResponseBody value) throws IOException {try {return value.bytes();} finally {value.close();}}}static final class StringRequestBodyConverter implements Converter<String, RequestBody> {@Overridepublic RequestBody convert(String value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}static final class ByteStringRequestBodyConverter implements Converter<ByteString, RequestBody> {@Overridepublic RequestBody convert(ByteString value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}static final class ByteArrayRequestBodyConverter implements Converter<byte[], RequestBody> {@Overridepublic RequestBody convert(byte[] value) throws IOException {return RequestBody.create(MEDIA_TYPE, value);}}
}
  • 功能概述ScalarsConverterFactory 用于处理基本数据类型(如 StringByteStringbyte[])的转换。它提供了响应体转换器和请求体转换器,分别用于将响应体转换为基本数据类型和将基本数据类型转换为请求体。
  • 响应体转换器:根据目标类型的不同,分别创建 StringResponseBodyConverterByteStringResponseBodyConverterByteArrayResponseBodyConverter,通过 ResponseBody 的相应方法读取数据并转换为目标类型。
  • 请求体转换器:根据源类型的不同,分别创建 StringRequestBodyConverterByteStringRequestBodyConverterByteArrayRequestBodyConverter,使用 RequestBody.create 方法将数据转换为 RequestBody
7.3.2 MoshiConverterFactory

java

public final class MoshiConverterFactory extends Converter.Factory {private final Moshi moshi;private final boolean lenient;private final boolean failOnUnknown;private final boolean serializeNulls;public static MoshiConverterFactory create() {return create(new Moshi.Builder().build());}public static MoshiConverterFactory create(Moshi moshi) {return new MoshiConverterFactory(moshi, false, false, false);}private MoshiConverterFactory(Moshi moshi, boolean lenient, boolean failOnUnknown, boolean serializeNulls) {this.moshi = moshi;this.lenient = lenient;this.failOnUnknown = failOnUnknown;this.serializeNulls = serializeNulls;}@Overridepublic Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {JsonAdapter<?> adapter = moshi.adapter(type);if (lenient) {adapter = adapter.lenient();}if (failOnUnknown) {adapter = adapter.failOnUnknown();}if (serializeNulls) {adapter = adapter.serializeNulls();}return new MoshiResponseBodyConverter<>(adapter);}@Overridepublic Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {JsonAdapter<?> adapter = moshi.adapter(type);if (lenient) {adapter = adapter.lenient();}if (failOnUnknown) {adapter = adapter.failOnUnknown();}if (serializeNulls) {adapter = adapter.serializeNulls();}return new MoshiRequestBodyConverter<>(adapter);}
}final class MoshiResponseBodyConverter<T> implements Converter<ResponseBody, T> {private final JsonAdapter<T> adapter;MoshiResponseBodyConverter(JsonAdapter<T> adapter) {this.adapter = adapter;}@Overridepublic T convert(ResponseBody value) throws IOException {try {return adapter.fromJson(value.source());} finally {value.close();}}
}final class MoshiRequestBodyConverter<T> implements Converter<T, RequestBody> {private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");private final JsonAdapter<T> adapter;MoshiRequestBodyConverter(JsonAdapter<T> adapter) {this.adapter = adapter;}@Overridepublic RequestBody convert(T value) throws IOException {Buffer buffer = new Buffer();adapter.toJson(buffer, value);return RequestBody.create(MEDIA_TYPE, buffer.readByteString());}
}
  • 功能概述MoshiConverterFactory 是基于 Moshi 库的转换器工厂,用于处理 JSON 数据的序列化和反序列化。Moshi 是一个轻量级的 JSON 解析库,性能较好。
  • 响应体转换器MoshiResponseBodyConverter 通过 JsonAdapterfromJson 方法将 ResponseBody 中的 JSON 数据转换为目标类型。
  • 请求体转换器MoshiRequestBodyConverter 通过 JsonAdaptertoJson 方法将目标类型的对象转换为 JSON 数据,并创建 RequestBody 对象。

八、请求拦截器和网络层处理

8.1 请求拦截器

在 Retrofit 中,可以通过 OkHttp 的拦截器对请求和响应进行拦截处理。以下是一个简单的请求拦截器示例:

java

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;import java.io.IOException;public class CustomInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {// 获取原始请求Request originalRequest = chain.request();// 可以对请求进行修改,例如添加请求头Request newRequest = originalRequest.newBuilder().header("Authorization", "Bearer your_token").build();// 继续执行请求return chain.proceed(newRequest);}
}

在创建 OkHttpClient 时添加该拦截器:

java

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new CustomInterceptor()).build();Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").client(client).build();
8.1.1 拦截器原理
  • Interceptor 接口定义了一个 intercept 方法,该方法接收一个 Chain 对象。Chain 对象包含了原始请求和处理请求的上下文信息。
  • intercept 方法中,可以对原始请求进行修改,例如添加请求头、修改请求参数等。
  • 调用 chain.proceed(newRequest) 方法继续执行修改后的请求,并返回响应。

8.2 网络层处理

Retrofit 底层使用 OkHttp 进行网络请求,OkHttp 提供了强大的网络层处理能力,包括连接池管理、缓存、重试机制等。

8.2.1 连接池管理

java

OkHttpClient client = new OkHttpClient.Builder().connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES)).build();

上述代码创建了一个连接池,最多允许 5 个空闲连接,每个连接的空闲时间最长为 5 分钟。连接池的作用是复用已经建立的连接,减少连接建立和关闭的开销,提高网络请求的性能。

8.2.2 缓存机制

java

File cacheDirectory = new File(context.getCacheDir(), "http_cache");
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10 MBOkHttpClient client = new OkHttpClient.Builder().cache(cache).build();

上述代码创建了一个缓存目录和一个大小为 10 MB 的缓存对象,并将其添加到 OkHttpClient 中。OkHttp 会根据响应头的 Cache-ControlExpires 字段来判断是否可以使用缓存,从而减少不必要的网络请求。

8.2.3 重试机制

OkHttp 本身没有提供内置的重试机制,但可以通过自定义拦截器来实现。以下是一个简单的重试拦截器示例:

java

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;import java.io.IOException;public class RetryInterceptor implements Interceptor {private static final int MAX_RETRIES = 3;@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();Response response = null;IOException exception = null;for (int i = 0; i < MAX_RETRIES; i++) {try {response = chain.proceed(request);if (response.isSuccessful()) {return response;}} catch (IOException e) {exception = e;}}if (exception != null) {throw exception;}return response;}
}

在创建 OkHttpClient 时添加该拦截器:

java

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new RetryInterceptor()).build();

该重试拦截器会在请求失败时最多重试 3 次,直到请求成功或达到最大重试次数。

九、错误处理和异常情况

9.1 网络请求错误处理

在使用 Retrofit 进行网络请求时,可能会遇到各种错误,例如网络连接失败、服务器返回错误状态码等。以下是处理这些错误的常见方式:

9.1.1 异步请求错误处理

java

Call<MyResponse> call = service.getMyData();
call.enqueue(new Callback<MyResponse>() {@Overridepublic void onResponse(Call<MyResponse> call, Response<MyResponse> response) {if (response.isSuccessful()) {MyResponse data = response.body();// 处理成功响应} else {try {// 获取错误响应体String errorBody = response.errorBody().string();// 处理错误响应} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void onFailure(Call<MyResponse> call, Throwable t) {// 处理请求失败,例如网络连接失败t.printStackTrace();}
});

onResponse 方法中,通过 response.isSuccessful() 判断响应是否成功,如果失败则可以通过 response.errorBody() 获取错误响应体。在 onFailure 方法中,处理请求失败的情况,例如网络连接失败、请求超时等。

9.1.2 同步请求错误处理

java

try {Call<MyResponse> call = service.getMyData();Response<MyResponse> response = call.execute();if (response.isSuccessful()) {MyResponse data = response.body();// 处理成功响应} else {try {// 获取错误响应体String errorBody = response.errorBody().string();// 处理错误响应} catch (IOException e) {e.printStackTrace();}}
} catch (IOException e) {// 处理请求失败,例如网络连接失败e.printStackTrace();
}

同步请求通过 try-catch 块捕获可能的 IOException 异常,在异常处理中可以处理网络连接失败等情况。

9.2 异常情况分析

9.2.1 注解使用错误

如果在 API 接口方法中使用注解不当,例如使用了不兼容的注解组合或注解参数错误,会在创建 ServiceMethodRequestFactory 时抛出异常。例如:

java

@GET("users/{user}")
@POST("users/{user}") // 错误:一个方法不能同时使用 @GET 和 @POST 注解
Call<ResponseBody> getUser(@Path("user") String user);

这种情况下,RequestFactorybuild 方法会抛出异常,提示只能使用一个 HTTP 方法注解。

9.2.2 类型转换异常

如果使用的 Converter 无法处理请求参数或响应结果的类型,会抛出类型转换异常。例如,使用 GsonConverterFactory 处理非 JSON 格式的数据,或者使用 ScalarsConverterFactory 处理复杂的对象类型。

9.2.3 网络连接异常

在网络请求过程中,可能会遇到网络连接失败、请求超时等异常。这些异常通常会在 OkHttpCallenqueueexecute 方法中抛出,并通过 CallbackonFailure 方法回调给调用者。

十、总结与展望

10.1 总结

通过对 Retrofit 请求执行模块的深入源码分析,我们了解了 Retrofit 的核心工作原理。从 Retrofit 实例的创建、接口代理对象的生成,到请求的执行、响应的处理,每个环节都有其独特的设计和实现。

  • 模块化设计:Retrofit 采用了高度模块化的设计,将不同的功能拆分成多个模块,如 CallAdapterConverterInterceptor 等。这种设计使得 Retrofit 具有很强的扩展性,开发者可以根据自己的需求替换或扩展这些模块。
  • 注解驱动:使用注解来定义 API 接口方法的请求信息,使得代码简洁、易读且易于维护。注解的使用也提高了代码的灵活性,开发者可以根据不同的需求选择不同的注解组合。
  • 与 OkHttp 集成:Retrofit 底层使用 OkHttp 进行网络请求,借助 OkHttp 的强大功能,如连接池管理、缓存、拦截器等,提高了网络请求的性能和稳定性。

10.2 展望

随着技术的不断发展,Retrofit 也可以在以下方面进行改进和拓展:

10.2.1 支持新的网络协议

随着 HTTP/3 等新的网络协议的逐渐普及,Retrofit 可以考虑支持这些新协议,以进一步提高网络请求的性能和安全性。

10.2.2 更好的异步编程支持

虽然 Retrofit 已经支持异步请求,但可以进一步优化对 Kotlin 协程、Java 异步流等异步编程模型的支持,使开发者能够更方便地进行异步编程。

10.2.3 增强错误处理和调试功能

可以提供更详细的错误信息和调试工具,帮助开发者更快地定位和解决问题。例如,在异常信息中提供更多的上下文信息,或者提供可视化的调试工具。

10.2.4 跨平台支持

除了 Android 和 Java 平台,Retrofit 可以考虑提供对其他平台的支持,如 iOS、Web 等,以扩大其应用范围。

综上所述,Retrofit 是一个优秀的网络请求框架,通过深入理解其源码和工作原理,开发者可以更好地使用和扩展该框架,提高开发效率和应用性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/32454.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EasyRTC嵌入式音视频通话SDK:基于纯C语言的跨平台实时通信系统设计与实践

随着物联网、移动互联网的快速发展&#xff0c;实时音视频通信技术在智能硬件、远程协作、工业控制等领域广泛应用。然而&#xff0c;跨平台兼容性差、资源占用高、定制化难等问题&#xff0c;仍是传统RTC方案的痛点。 EasyRTC嵌入式音视频通话SDK凭借纯C语言设计与全平台覆盖…

HCIP复习拓扑练习(修改版)

拓扑&#xff1a; 实际&#xff1a; 需求&#xff1a; 需求分析 1.这意味着学校内部网络能够正常解析域名并进行互联网访问。 2. PC1和PC2处于同一个内网192.168.1.0/24&#xff0c;其中PC1有权限访问外部网段3.3.3.0/24&#xff0c;而PC2没有。这涉及ACL&#xff08;访问控制…

vue-next-admin修改配置指南

目录 1.如何开启侧边栏logo 2.修改侧边栏顶部的logo与文字 3.修改侧边栏路由logo 4.浏览器标题栏图标与文字修改 5.修改侧边栏的背景颜色、顶部导航栏背景颜色、字体颜色、激活时颜色等 6.去除或添加修改右上方放大、信息、头像昵称&#xff08;登录获取之后存储进行修改图…

ruoyi-cloud-plus编译记录-1

dockerfile部署jar 添加一个run configuration ‘ruoyi-nacos’ run configuration 参考Docker - 在IntelliJ IDEA中一键部署项目 - hucat - 博客园 jar包编译不成功&#xff0c;没有jar&#xff0c;docker部署nacos就没法进行下去 参考链接 maven 构建报错 This failure was…

【算法day8】整数反转

整数反转 https://leetcode.cn/problems/reverse-integer/description/ class Solution { public:int reverse(int x) {int MAX_LENGTH 11; // 32位整数的最大数字的位数int* num (int*)calloc(sizeof(int), MAX_LENGTH); //用于保存进位每一位的数字int current x;int pos…

MySQL库和表的操作详解:从创建库到表的管理全面指南

目录 一、MySQL库的操作详解 〇、登录MySQL 一、数据库的创建与字符集设置 1. 创建数据库的语法 2. 创建数据库示例 查看创建出来的文件: bash下查看MySQL创建的文件 二、字符集与校验规则 1. 查看系统默认设置 2. 查看支持的字符集与校验规则 3. 校验规则对查询的影响…

Linux中的基本指令(上)

目录 ls指令 判断linux中文件 pwd指令 认识路径 ​编辑 绝对路径/相对路径 cd指令 简要理解用户 理解家目录 echo指令和printf指令 touch指令 mkdir指令 cat指令 tree指令 rmdir指令和rm指令 man指令 cp指令 which指令 alias 指令 date指令 cal指令 理解…

WPF 与 GMap.NET 结合实现雷达目标动态显示与地图绘制

概述 雷达上位机是雷达系统中用于数据可视化、分析和控制的核心软件。本文将介绍如何使用 C# 和 WPF 框架开发一个雷达上位机程序&#xff0c;主要功能包括&#xff1a; 显示目标轨迹&#xff1a;在界面上实时绘制雷达探测到的目标轨迹。点击显示详细信息&#xff1a;用户点击…

「string」笔记

参考&#xff1a;比特鹏哥 1. string string是一种类型&#xff0c;指的是字符串&#xff0c;比字符数组更高级 头文件 <string> #include <string>int main() {string a;//未初始化string b "good good";//初始化string c("good sfternoon&q…

AutoGen使用学习

AutoGen使用学习 上篇文件使用使用【autoGenchainlitdeepSeek】实现【多角色、多用户、多智能体对话系统】&#xff0c;本次系统的学习autoGen的使用方法 文章目录 AutoGen使用学习[toc]1-核心知识点2-参考网址3-实战案例1-autoGen安装和基础使用主要功能安装方法使用示例注意事…

207、【图论】孤岛的总面积

题目 思路 相比于 206、【图论】岛屿数量&#xff0c;就是在这个代码的基础上。先遍历边界&#xff0c;将边界连接的岛屿变为0&#xff0c;然后再计算一遍当前为1的岛屿面积。 代码实现 import collectionsn, m list(map(int, input().split())) graph []for _ in range(n…

Python Selenium库入门使用,图文详细。附网页爬虫、web自动化操作等实战操作。

文章目录 前言1 创建conda环境安装Selenium库2 浏览器驱动下载&#xff08;以Chrome和Edge为例&#xff09;3 基础使用&#xff08;以Chrome为例演示&#xff09;3.1 与浏览器相关的操作3.1.1 打开/关闭浏览器3.1.2 访问指定域名的网页3.1.3 控制浏览器的窗口大小3.1.4 前进/后…

在芯片设计的后端流程中,通过metal修timing是什么意思,怎么实施。举个timing违例说明一下

芯片设计后端流程中通过Metal修Timing 在芯片设计后端流程中&#xff0c;"通过metal修timing"是指通过调整金属层布线来解决时序违例问题的一种技术手段。这是物理设计阶段常用的优化方法之一。 什么是通过Metal修Timing 在芯片设计中&#xff0c;Metal&#xff08;金…

【数据结构】List介绍

目录 1. 什么是List 2. 常见接口介绍 3. List的使用 1. 什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。此时extends意为拓展 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下所示&…

文件上传漏洞

pass-1 判断本关文件上传检测方式 ①显示源码 本pass在客户端使用js对不合法图片进行检查!js前端检测 2、针对防御措施进行绕过上传 通过JS 限制上传的文件类型&#xff0c;对于这种情况&#xff0c;我们可以采用以下几种方式绕过&#xff1a; 修改JS文件; 上传png后缀的…

深入Flink运行时架构:JobManager与TaskManager协作全解析

深入Flink运行时架构:JobManager与TaskManager协作全解析 一、Flink分布式执行模型剖析 1.1 运行时架构全景视图 核心组件交互关系: #mermaid-svg-tMSqMSsKP6vwUZi3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-s…

股票-K线

一根K线记录的是某股票一个周期的价格变动情况,其周期可以分为月k线、周k线、日k线、小时线等等。 单根K线的构成要素,通常有以下几部分: 开盘价、收盘价、最高价、最低价、实体、上影线、下影线。 1、阳K线 在阳K线中, 最上端的线段为上影线,上影线的最高点为最高价,…

行为模式---策略模式

概念 策略模式是一种行为设计摸是&#xff0c;它的核心思想是将一些列的算法封装成独立的对象&#xff0c;并使它们可以相互替换&#xff0c;通过上下文进行调用。 策略模式通过算法抽象为独立的策略类&#xff0c;客户端可以根据自身需求选择不同的策略类来完成任务、这种方…

3.3.2 Proteus第一个仿真图

文章目录 文章介绍0 效果图1 新建“点灯”项目2 添加元器件3 元器件布局接线4 补充 文章介绍 本文介绍&#xff1a;使用Proteus仿真软件画第一个仿真图 0 效果图 1 新建“点灯”项目 修改项目名称和路径&#xff0c;之后一直点“下一步”直到完成 2 添加元器件 点击元…

Diffusion-Probabilistic-Models环境配置

1、相关地址 代码地址:https://github.com/Sohl-Dickstein/Diffusion-Probabilistic-Models 论文地址:https://arxiv.org/abs/2006.11239 2、python2.7 环境安装 conda create -n theano python2.7 -y conda activate theano3、包安装 下载合适的版本&#xff0c;也就是201…