Retrofit对动态代理模式的利用是最巧妙的。你需要事先理解动态代理模式的实现原理
动态代理模式中,系统会自动实现需要代理的接口,自动生成一个代理类的.class文件,这个自动生成的代理类中,所有的代理方法都是调用InvocationHandler对象。这一点是最重要的。方便参数以注解的方式在各接口方法上定义好。
如何理解上面加黑的那句话呢? 请看下面的代码:
public interface RetrofitService{
@GET("/service/get/")
Call<ResponseInfo<User>> get(@HeaderMap Map<String, String>header, @Query("userId") String id);
}
public class RetrofitService$12345 implement RetrofitService{
private InvocationHandler handler;
public RetrofitService$12345(InvocationHandler handler){
this.handler = handler;
}
@GET("/service/get/")
public Call<ResponseInfo<User>> get(@HeaderMap Map<String, String>header,
@Query("userId") String id){
return handler.invoke(null,
RetrofitService.getClass().getMethod("get"),
new Objectt[]{header, id});
}
}
- RetrofitService是开发者定义的http访问接口。
- RetrofitService$12345是系统自动生成的代理类,它实现了RetrofitService。
- RetrofitService目前只有一个get方法, 即使更多的方法, 里面也是调用handler.invoke()。
下面看看Retrofit中使用动态代理的create方法。
public <T> T create(final Class<T> service) {
validateServiceInterface(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);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
- 由于每一个接口方法都只调用传进去的new InvocationHandler()对象。使得所有的接口方法都会调到 Object invoke()这个方法里来。
- 接下来的操作,就是解析注解,封装request, 封装Call, 返回Call或者通过CallAdapter返回其他可执行Call的对象。如下图:
- platform.isDefaultMethod(method), 是判断接口方法是不是interface里面的default方法,这是java8的语言特性, 在interface里面也可以定义方法体。
- platform.invokeDefaultMethod(method, service, proxy, args), 如果这个方法是接口default方法, 就调用这个defualt方法。
- 以上两点对retrofit的使用都不重要,作者只是为了把异常case写全。重要的是loadSerivceMethod()这个方法。