Retrofit(源码)
一、回顾使用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
二、源码解析-创建代理对象
retrofit.create(GitHubService.class) 做了如下几件事情
- 判断class 是否符合要求(只能是nterface ,并且不能继承别的接口)
- 是否提前验证接口
- 创建代理对象返回(JDK 代理)
public <T> T create(final Class<T> service) {
//判断class 是否符合要求(只能是nterface ,并且不能继承别的接口)
Utils.validateServiceInterface(service);
//是否提前验证接口
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//返回代理对象
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//如果是default方法,调用default方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//构造ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
// Prevent API interfaces from extending other interfaces. This not only avoids a bug in
// Android (http://b.android.com/58753) but it forces composition of API declarations which is
// the recommended pattern.
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
根据上面代码可以很请吃的看到,创建代理的核心逻辑在loadServiceMethod()方法中,下面更进一步看一下该方法的实现逻辑。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
ServiceMethod.Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations(); //方法上面的注解
this.parameterTypes = method.getGenericParameterTypes(); //参数类型
this.parameterAnnotationsArray = method.getParameterAnnotations();//参数注解
}
核心逻辑build()方法中,build()方法做的几件事
- 创建createCallAdapter
- responseType类型判断
- 获取responseBody类型转换器
- 解析方法注解
- 解析参数注解
// 可简单看下此处源码,下面有每一步具体做的事情
public ServiceMethod build() {
//创建createCallAdapter
callAdapter = createCallAdapter();
//responseType类型判断
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
//获取responseBody类型转换器
/**
次处对应:this.builder = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(JacksonConverterFactory.create());
*/
responseConverter = createResponseConverter();
//解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
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];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
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;
}
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
if (this.httpMethod != null) {
throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
this.httpMethod, httpMethod);
}
this.httpMethod = httpMethod;
this.hasBody = hasBody;
if (value.isEmpty()) {
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);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
int colon = header.indexOf(':');
if (colon == -1 || colon == 0 || colon == header.length() - 1) {
throw methodError(
"@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
}
String headerName = header.substring(0, colon);
String headerValue = header.substring(colon + 1).trim();
if ("Content-Type".equalsIgnoreCase(headerName)) {
MediaType type = MediaType.parse(headerValue);
if (type == null) {
throw methodError("Malformed content type: %s", headerValue);
}
contentType = type;
} else {
builder.add(headerName, headerValue);
}
}
return builder.build();
}
创建createCallAdapter
1、类型判断(不支持TypeVariable or WildcardType) TypeVariable(类型变量):比如List< T >中的T,U,V等。TypeVariable有getBounds()界限数组和getGenericDeclaration()定义在哪个类中的方法。而List< T >是ParameterizedType,ParameterizedType的getRawType是List; getActualTypeArguments是T,T是TypeVariable,
WildcardType( 通配符类型):例如List< ? extends Number>中的? extends Number,WildcardType有上下界方法。而List< ? extends Number>本身是ParameterizedType,ParameterizedType的getRawType()方法获取到的是List; getActualTypeArguments是? extends Number,? extends Number是WildcardType。
2、void 不支持
3、返回CallAdapter
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
};
}
三、源码解析-调用
Call<List<Repo>> repos = service.listRepos("octocat");
repos.execute();
Call.execute() 方法
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
//重复调用过滤
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else if (creationFailure instanceof RuntimeException) {
throw (RuntimeException) creationFailure;
} else {
throw (Error) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall(); 、、
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
okhttp3.Call toCall(@Nullable 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]);
}
// 创建requestBuilder() callFactoruy.newCall = OkHttpClient.newCall
/**
OkHttpClient client = ...
OkHttpClient clientWith30sTimeout = client.newBuilder()
.readTimeout(30, TimeUnit.SECONDS)
.build();
Response response = clientWith30sTimeout.newCall(request).execute();
*/
return callFactory.newCall(requestBuilder.build());
}
四、总结
Retrofit.create 创建代理对象- 解析注解
- 生成S
erviceMethod
- 请求方法获得代理对象(Call)
- Call.
execute执行http请求逻辑- 请求参数对应 serviceMethod.toCall()
- 返回值序列化
- 返回值解析对应ServcieMethod.
toResponse()
- 返回值解析对应ServcieMethod.