Retrofit使用注解,使网络请求的代码特别简洁,但是内部是怎样通过注解转换成一个正常格式的网络请求链接的呢?
阅读源码理解如下:
POST注解
/**
* 登录
*
* @return
*/
@POST("service-auth/login")
Observable<Result> login(@Query("userPhone") String userPhone, @Query("userPwd") String userPwd);
点击POST看看他是什么
/** Make a POST request. */
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
/**
* A relative or absolute path, or full URL of the endpoint. This value is optional if the first
* parameter of the method is annotated with {@link Url @Url}.
* <p>
* See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
* this is resolved against a base URL to create the full endpoint URL.
*/
String value() default "";
}
@Target(METHOD)说明这是一个方法注解
@Retention(RUNTIME) 表示需要在什么级别保存该注解信息
然后我们找找POST注解在哪使用了:
ServiceMethod
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError("HEAD method must use Void as response type.");
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} 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 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("@Headers annotation is empty.");
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
if (isFormEncoded) {
throw methodError("Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
throw methodError("Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
发现在ServiceMethod中被使用了。
image.png
。
ServiceMethod
public ServiceMethod build() {
...
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
}
ServiceMethod
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
Retrofit
ServiceMethod<?, ?> loadServiceMethod(Method method) {
...
result = new ServiceMethod.Builder<>(this, method).build();
...
}
Retrofit
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
整个过程从上到下是,1.传给eagerlyValidateMethods一个Class对象,
2.通过反射 service.getDeclaredMethods()从Class的得到Method,
3.this.methodAnnotations = method.getAnnotations();从Method获得方法的注解,4.在 parseMethodAnnotation中根据获取的注解做分支操作。
使用时,在
ServiceFactory.getInstance()
.createService(AccountService.class)
.login(userCode, pwd);
被执行时,注解修饰的interface login()方法
/**
* 登录
*
* @return
*/
@POST("service-auth/login")
Observable<Result> login(@Query("userPhone") String userPhone, @Query("userPwd") String userPwd);
就被转化为post 请求形式。
curl -X POST "http://xxx.service-auth/login?userPhone=1&userPwd=1" -H "accept: */*" -H "token: 1"
参考: 对注解的使用,和自定义注解有一定的了解后,会更容易理解理解Retrofit的注解。
网友评论