上篇文章已经介绍了Retrofit里面的大多数类,今天就重点介绍ServiceMethod,本片文章主要内容如下:
为了方便后面学习ServiceMethod,我们先来看下ParameterHandler类
从字面意思我们猜到 他是参数处理类。具体是不是那?用源码说话,看源码
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, T value) throws IOException;
final ParameterHandler<Iterable<T>> iterable() {
return new ParameterHandler<Iterable<T>>() {
@Override void apply(RequestBuilder builder, Iterable<T> values) throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}
final ParameterHandler<Object> array() {
return new ParameterHandler<Object>() {
@Override void apply(RequestBuilder builder, @Nullable Object values) throws IOException {
if (values == null) return; // Skip null values.
for (int i = 0, size = Array.getLength(values); i < size; i++) {
//noinspection unchecked
ParameterHandler.this.apply(builder, (T) Array.get(values, i));
}
}
};
}
//由于篇幅的限制,我没有粘贴静态内部类
}
通过简单阅读源代码,我们得知:
这里说下iterable()方法和array()方法,说明ParameterHandler是支持两种数据类型的处理方式。一个是对应迭代器(iterable)的类型;一个是对应的是数组类型的。所以我们继续往下看
看下源码:
static final class RelativeUrl extends ParameterHandler<Object> {
@Override void apply(RequestBuilder builder, Object value) {
builder.setRelativeUrl(value);
}
}
看下源码:
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 = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addHeader(name, valueConverter.convert(value));
}
}
看下源码:
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Path(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) {
throw new IllegalArgumentException(
"Path parameter \"" + name + "\" value must not be null.");
}
builder.addPathParam(name, valueConverter.convert(value), encoded);
}
看下源码:
static final class Query<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Query(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addQueryParam(name, valueConverter.convert(value), encoded);
}
}
看下源码:
static final class QueryName<T> extends ParameterHandler<T> {
private final Converter<T, String> nameConverter;
private final boolean encoded;
QueryName(Converter<T, String> nameConverter, boolean encoded) {
this.nameConverter = nameConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addQueryParam(nameConverter.convert(value), null, encoded);
}
}
看下源码:
static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {
private final Converter<T, String> valueConverter;
private final boolean encoded;
QueryMap(Converter<T, String> valueConverter, boolean encoded) {
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("Query map was null.");
}
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
if (entryKey == null) {
throw new IllegalArgumentException("Query map contained null key.");
}
T entryValue = entry.getValue();
if (entryValue == null) {
throw new IllegalArgumentException(
"Query map contained null value for key '" + entryKey + "'.");
}
builder.addQueryParam(entryKey, valueConverter.convert(entryValue), encoded);
}
}
}
看下源码:
static final class HeaderMap<T> extends ParameterHandler<Map<String, T>> {
private final Converter<T, String> valueConverter;
HeaderMap(Converter<T, String> valueConverter) {
this.valueConverter = valueConverter;
}
@Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("Header map was null.");
}
for (Map.Entry<String, T> entry : value.entrySet()) {
String headerName = entry.getKey();
if (headerName == null) {
throw new IllegalArgumentException("Header map contained null key.");
}
T headerValue = entry.getValue();
if (headerValue == null) {
throw new IllegalArgumentException(
"Header map contained null value for key '" + headerName + "'.");
}
builder.addHeader(headerName, valueConverter.convert(headerValue));
}
}
}
看下源码:
static final class Field<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
Field(String name, Converter<T, String> valueConverter, boolean encoded) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, T value) throws IOException {
if (value == null) return; // Skip null values.
builder.addFormField(name, valueConverter.convert(value), encoded);
}
}
看下源码:
static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
private final Converter<T, String> valueConverter;
private final boolean encoded;
FieldMap(Converter<T, String> valueConverter, boolean encoded) {
this.valueConverter = valueConverter;
this.encoded = encoded;
}
@Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("Field map was null.");
}
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
if (entryKey == null) {
throw new IllegalArgumentException("Field map contained null key.");
}
T entryValue = entry.getValue();
if (entryValue == null) {
throw new IllegalArgumentException(
"Field map contained null value for key '" + entryKey + "'.");
}
builder.addFormField(entryKey, valueConverter.convert(entryValue), encoded);
}
}
}
看下源码:
static final class Part<T> extends ParameterHandler<T> {
private final Headers headers;
private final Converter<T, RequestBody> converter;
Part(Headers headers, Converter<T, RequestBody> converter) {
this.headers = headers;
this.converter = converter;
}
@Override void apply(RequestBuilder builder, T value) {
if (value == null) return; // Skip null values.
RequestBody body;
try {
body = converter.convert(value);
} catch (IOException e) {
throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
}
builder.addPart(headers, body);
}
}
看下源码:
static final RawPart INSTANCE = new RawPart();
private RawPart() {
}
@Override void apply(RequestBuilder builder, MultipartBody.Part value) throws IOException {
if (value != null) { // Skip null values.
builder.addPart(value);
}
}
看下源码:
static final class PartMap<T> extends ParameterHandler<Map<String, T>> {
private final Converter<T, RequestBody> valueConverter;
private final String transferEncoding;
PartMap(Converter<T, RequestBody> valueConverter, String transferEncoding) {
this.valueConverter = valueConverter;
this.transferEncoding = transferEncoding;
}
@Override void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
if (value == null) {
throw new IllegalArgumentException("Part map was null.");
}
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
if (entryKey == null) {
throw new IllegalArgumentException("Part map contained null key.");
}
T entryValue = entry.getValue();
if (entryValue == null) {
throw new IllegalArgumentException(
"Part map contained null value for key '" + entryKey + "'.");
}
Headers headers = Headers.of(
"Content-Disposition", "form-data; name=\"" + entryKey + "\"",
"Content-Transfer-Encoding", transferEncoding);
builder.addPart(headers, valueConverter.convert(entryValue));
}
}
}
看下源码:
static final class Body<T> extends ParameterHandler<T> {
private final Converter<T, RequestBody> converter;
Body(Converter<T, RequestBody> converter) {
this.converter = converter;
}
@Override void apply(RequestBuilder builder, T value) {
if (value == null) {
throw new IllegalArgumentException("Body parameter value must not be null.");
}
RequestBody body;
try {
body = converter.convert(value);
} catch (IOException e) {
throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
}
builder.setBody(body);
}
}
本来这篇内容应该放到上一篇文章中,但是由于受到篇幅限制的原由,所以放到这里了,看完ParameterHandler类的源码在回想下ParameterHandler的源码,大家有没有想到一些东西?
其实Retrofit团队是这样分工的,RequestBuilder仅仅是一个包装类,但是具体的赋值操作等其实是通过ParameterHandler对应的静态内部类来实现的,这样实现了包装和操作分离,实现了解耦。多么"优雅"的设计。
首先用类注解解释下ServiceMethod是什么?
/** Adapts an invocation of an interface method into an HTTP call. */
我翻译一下:
将一个接口的方方法的调用适配成一个HTTP的Call。
我的理解是:
ServiceMethod是一个负责转化(适配)的类,负责把一个接口的抽象方法的执行过程的结果转化(适配)成一个网络请求(HTTP call)。
ok 那我们来看下他的源码
由于这个类略大,一直在纠结要不要把全部代码粘贴上,但是考虑到大家的情况,还是粘贴了,不过省略了Buidler内部静态类的代码,希望大家理解。
/** Adapts an invocation of an interface method into an HTTP call. */
final class ServiceMethod<R, T> {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
final okhttp3.Call.Factory callFactory;
final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<ResponseBody, R> responseConverter;
private final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
/** Builds an HTTP request from method arguments. */
Request toRequest(Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
//省略了Builder内部类
}
通过错略看过源代码可以获取如下信息:
大家先来看下变量,由于变量不多,我直接上注释了。
//用来校验的常量
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
//网络请求call的工厂,注释是okhttp3的
final okhttp3.Call.Factory callFactory;
// 网络请求适配器
final CallAdapter<R, T> callAdapter;
//基础HttpUrl
private final HttpUrl baseUrl;
//响应转化器
private final Converter<ResponseBody, R> responseConverter;
//网络请求的方法
private final String httpMethod;
//网络请求url的相对路径
private final String relativeUrl;
// 请求头
private final Headers headers;
//请求类型
private final MediaType contentType;
//是否有请求体
private final boolean hasBody;
//是否是表单提交
private final boolean isFormEncoded;
//以二进制流的方式提交
private final boolean isMultipart;
//参数处理器。具体在后面讲解
private final ParameterHandler<?>[] parameterHandlers;
/** Builds an HTTP request from method arguments. */
Request toRequest(Object... args) throws IOException {
//new 了一个RequestBuilder对象
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
//获取入参的个数
int argumentCount = args != null ? args.length : 0;
if (argumentCount != handlers.length) {
throw new IllegalArgumentException("Argument count (" + argumentCount
+ ") doesn't match expected count (" + handlers.length + ")");
}
//遍历入参
for (int p = 0; p < argumentCount; p++) {
//配置对应的requestBuilder属性
handlers[p].apply(requestBuilder, args[p]);
}
//调用requestBuilder的build()方法获取一个okhttp3.request对象
return requestBuilder.build();
}
通过注释我们发现,其实这个方法是:
通过方法的入参来够将一个HTTP的请求。
方法内的大体流程如下:
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
通过方法注释我们得知:
通过一个HTTP的响应体(response body)来构建一个方法的返回值。
方法很简单就一行,就是调用响应解析/处理器(responseConverter)的convert方法来解析/反序列化响应体。
/**
* Inspects the annotations on an interface method to construct a reusable service method. This
* requires potentially-expensive reflection so it is best to build each service method only once
* and reuse it. Builders cannot be reused.
*/
翻译一下就是
通过检查接口方法上的注解来构建一个可以重用的 "服务方法",由于用到高性能消耗的反射,所以最好一个 "服务方法" 只构建一次,并且可以重复使用。Builders不能被重用
我的理解是:
其实Retrofit内部是通过动态代理,内部是通过反射实现的,大家都知道反射其实是很消耗性能的,为了避免这种高性能的消耗,反射成功以后就缓存起来,下次如果有用到就重用,如果不能重用则用反射构建出来,但是Builder是不能重用的。
由于Builder源码太多了,我就不上源码了 我们来看下Builder类的变量,我直接标注释了
//Retrofit
final Retrofit retrofit;
//定义接口的抽象方法
final Method method;
//定义接口的抽象方法上面的注解数组
final Annotation[] methodAnnotations;
//注解二维数组:第一维对应参数序列,第二维对应注解序列;
final Annotation[][] parameterAnnotationsArray;
// 参数类型数组
final Type[] parameterTypes;
// 响应的类型
Type responseType;
//是否有用 @Field 或者FieldMap 注解
boolean gotField;
//是否 有用@Part 或者 @PartMap注解
boolean gotPart;
//是否有用 @body注解
boolean gotBody;
// 是否 有用@Path 注解
boolean gotPath;
//是否 有用@Query 或者@QueryName 注解
boolean gotQuery;
// 是否具有url
boolean gotUrl;
//http 请求的方法
String httpMethod;
//是否 需要请求体
boolean hasBody;
//是否 使用@FormUrlEncoded 注解
boolean isFormEncoded;
// 是否 使用了@Multipart 注解
boolean isMultipart;
// 相对路径
String relativeUrl;
//请求头
Headers headers;
//类型
MediaType contentType;
//相对路径的url参数
Set<String> relativeUrlParamNames;
//参数处理数组
ParameterHandler<?>[] parameterHandlers;
//响应转化器
Converter<ResponseBody, T> responseConverter;
//请求转化器
CallAdapter<T, R> callAdapter;
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
通过构造函数我们知道Builder类里面的5个变量已经被初始化了
public ServiceMethod build() {
//通过调用createCallAdapter()方法获取callAdapter
callAdapter = createCallAdapter();
//通过调用callAdapter的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?");
}
//通过createResponseConverter()方法获取响应转化器
responseConverter = createResponseConverter();
//遍历方法的注解
for (Annotation annotation : methodAnnotations) {
//解析方法注解
parseMethodAnnotation(annotation);
}
//如果没有HTTP请求的方法,则抛异常
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//在上面遍历方法注解并解析方法注解的时候,hasBody,isMultipart,isFormEncoded等已经完成赋值
//如果没有请求体
if (!hasBody) {
//但是 还是使用了@Multipart注解,使用了@Multipart 是一定有消息体的
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
//但是 还是使用了 @FormEncoded,使用了@FormEncoded 是一定有消息体的
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
//如果方法 入参的注解,它的长度也就是有多少个入参,遍历每个入参对应的注解
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];
//如果对应入参的注解为null,则抛异常
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
//如果对应的入参注解不为null,则调用parseParameter方法获取ParameterHandler,cancel在这里方法里面创建ParameterHandler里面的静态内部类,后面咱们再仔细看下。
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
//for循环遍历以后,如果relativeUrl还为null,同时没有使用!@url注解,这样的话我们就无法获取url地址了,所以要抛异常。
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
//如果没有使用@FormEncoded注解、@Multipart和,同时HTTP请求方式也不需要响应提,但是却使用了@Body 注解,这不是自相矛盾,所以抛异常。
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
//如果使用@FormEncoded注解,却没使用@Field注解,不符合规范,则抛异常
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
//如果使用 @Multipart 注解,却没有使用@Part 注解,抛异常
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
//走到这里说明没有问题,则new一个ServiceMethod对象,入参是Builder自己,然后return这个ServiceMethod对象。
return new ServiceMethod<>(this);
}
大体流程如下:
自此整个build流程已经全部解析完毕,那我们在看来里面设计的其它方法
通过方法字面的含义我们理解为这个方法创建CallAdatper,具体我们看下源码:
private CallAdapter<T, R> createCallAdapter() {
//获取方法的返回值类型
Type returnType = method.getGenericReturnType();
//如果方法的返回值类型我们无法处理,则抛出异常
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
//如果方法是void的,则没有返回值
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//获取方法的注解
Annotation[] annotations = method.getAnnotations();
try {
//调用retrofit的callAdapter来获取一个CallAdapter对象
//noinspection unchecked
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
大体流程如下:
这个方法看字面的意思就知道是一个处理方法的注解,具体以源码为准。
private void parseMethodAnnotation(Annotation annotation) {
//如果是DELETE注解 代表DELETE请求
if (annotation instanceof DELETE) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
//如果是GET 注解,则代表是get请求
} else if (annotation instanceof GET) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
//如果是 HEAD注解,则代表HEAD请求,这里不是请求头,HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。
} else if (annotation instanceof HEAD) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
//HEAD请求是没有响应体的
throw methodError("HEAD method must use Void as response type.");
}
//如果是PATCH请求
} else if (annotation instanceof PATCH) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
//如果是PUT请求
} else if (annotation instanceof PUT) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
//如果是 OPTIONS注解,代表OPTIONS请求
} else if (annotation instanceof OPTIONS) {
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
//如果是@HTTP 注解,则代表自定义 HTTP请求
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
//调用parseHttpMethodAndPath()
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
//如果是 注解Headers 则代表请求头
} else if (annotation instanceof retrofit2.http.Headers) {
//获取对应的String 数组
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
//判断数组长度
if (headersToParse.length == 0) {
//这里可见如果一定使用@Headers 注解,则一定要有内容,否则会报错。
throw methodError("@Headers annotation is empty.");
}
//调用parseHeaders()方法来解析headersToParse
headers = parseHeaders(headersToParse);
//如果 是Multipart注解,则代表用文件提交
} else if (annotation instanceof Multipart) {
//如果是文件提交,则不能使用表单提交,这是互斥的
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
//给isMultipart赋值为true
isMultipart = true;
//如果 是 FormUrlEncoded注解,则代表表单提交
} else if (annotation instanceof FormUrlEncoded) {
由于和文件提交互斥,要判断
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
//给isFormEncoded赋值
isFormEncoded = true;
}
}
这个没什么流程,就是不断if else的过程,其中先是判断注解的类型,根据不同的类型来调用parseHttpMethodAndPath方法,这里主要指的是DELETE、GET、HEAD、PATCH、POST、PUT、OPTIONS请求,当然也包括自定义的HTTP请求。然后判断如果Headers,则说明要向请求头里面添加数据。最后做了表单提交和二进制流提交的互斥。那我们接来下就来看下对应的parseHttpMethodAndPath()方法。
通过方法名,我们理解这个方法主要是"解析HTTP的请求方法和路径",我们一起来看下源码
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
//因为Http请求只能设置一种请求方式,所以先做判断是否已经设置过请求方式,如果设置过则不能重复设置
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()) {
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("URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
//把value设置为相对路径的值
this.relativeUrl = value;
//最后调用parsePathParameters方法来放置出现重复参数
this.relativeUrlParamNames = parsePathParameters(value);
}
大体流程如下:
这个方法看方法名,可以理解解析请求头
private Headers parseHeaders(String[] headers) {
//new 了一个Headers.Builder()对象
Headers.Builder builder = new Headers.Builder();
//遍历 字符串数组
for (String header : headers) {
获取':'的position下标
int colon = header.indexOf(':');
//如果不存在字符':',或者在最前面,或者在最后面 这是不符合header标准,所以抛异常
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw methodError(
"@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
}
//按照':'分类,在':'前面为name,在':'后面为value
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
//按照忽略大小写的方法来判断是否是"Content-Type"。
if ("Content-Type".equalsIgnoreCase(headerName)) {
如果是"Content-Type",则来获取类型
MediaType type = MediaType.parse(headerValue);
//类型不能为null
if (type == null) {
throw methodError("Malformed content type: %s", headerValue);
}
把类型赋给contentType
contentType = type;
} else {
//如果不是"Content-Type",则添加到 Headers.Builder 里面
builder.add(headerName, headerValue);
}
}
//调用Headers.Builder的build()方法来返回一个okhttp3.Headers对象
return builder.build();
}
由于受到简书的篇幅限制,剩下的内容我们将在下一篇文章中解读