Retrofit - 从Retrofit.create说起
基于retrofit-2.6.2
代码
interface GitHubService {
@GET("users/{user}/repos")
fun listRepos(@Path("user") user: String?): Call<List<Repo?>?>?
}
val service = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build()
.create(GitHubService::class.java)
val repos = service.listRepos("octocat")
Retrofit实现create方法
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable 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);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类的加载器(你通常可以从已经被加载的对象中获取类加载器,然后传递它),一个你希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器。
——— 《java编程思想》
可以看到create方法其实是通过动态代理的方式创建了一个Service接口的代理类对象,该代理类实现了Service接口。代码中创建的InvocationHandler接口实例即是调用处理器,即之后对所有的代理类进行的Service接口方法的调用,最终都会被重定向到InvocationHandler的invoke方法。
例如上述代码执行
service.listRepos("octocat")
调用时,最终是执行的InvocationHandler的invoke方法。
通常的动态代理里的实现方式都是在创建的InvocationHandler实例中持有一个被代理类对象,然后在invoke方法中调用被代理类对象的方法,这样来实现代理过程。而Retrofit这里并不需要创建了一个被代理类实例,因为Retrofit这里只是为了获取在接口方法里添加的各种注解还有调用时使用的参数。真正执行的方法不需要外部去构建实现,而是封装在了Retrofit内部,即真正的实现是在这里:
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
loadServiceMethod方法返回的是一个ServiceMethod对象,最终调用的是ServiceMethod对象的invoke方法,并将实际的参数传递了进去。
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
loadServiceMethod方法首先会尝试从缓存中读取对应的ServiceMethod,没有的话再去根据method创建。创建的过程其实是获取method上标记的所有注解,以及注解里的参数值,通过这些来创建一个正真的ServiceMethod,在该对象里描述里请求相关的配置信息,用来构建真实的reuqest。因为这里做了缓存,所以,每个接口的注解解析只需要执行一次即可,之后都会从缓存中读取。