
大家好,我是Nixo,一枚刚毕业的Android小生,这是我开坑源码系列的第一篇文章,可能我的文章跟其他人不同,我的文章并不像别人那样的细枝末节所以我将本系列的文章称为"简要解析"主要是让大家明白整个框架它的实现流程,用了什么样的技术去实现什么功能之所以用Retrofit作为我的第一个阅读的框架是因为他的设计模式用的如火纯情,非常值得我们学习。
因为本人技术有限,如果有不好的地方或者错误的地方希望大家指正。
Retrofit源码简要解析系列共有3篇文章加上番外篇2篇总共5篇 :
-
Retrofit源码简要解析(一)Retrofit是怎样将接口转变为类来使用的(动态代理)
-
Retrofit源码简要解析(二)Retrofit是怎样将接口抽象方法转变为请求体的(注解处理器)
-
Retrofit源码简要解析(三)Retrofit是怎样将返回体转变为实体类的(反射、CallAdapted、CallAdapterFactory)
-
Retrofit源码简要解析番外(一)CallAdapterFactory对RxJava的支持
-
Retrofit源码简要解析番外(二)CallAdapterFactory对Kotlin协程的支持
今天我们来讲一下Retrofit是怎么将接口转为类来供我们使用的,其实这里说的不够准确,因为这个类已经不是我们声明的接口类了,可能我这么一说接口和类大家可能一时反应不过来我贴一个代码大家就会恍然大悟,原来你指的是这个!
//GitHubApi.class 就是我所述的接口,里面定义了Retrofit的网络请求抽象方法
//GitHubApi就是我所述的生成类
GitHubApi gitHubApi = retrofit.create(GitHubApi.class);
Call<List<GitHubApi.Contributors>> contributors =
gitHubApi.contributors("square", "retrofit",new Date());
如上代码Retrofit是怎么一番操作将我们的接口变为具体的类呢?这里用到了Java的动态代理(Proxy),带着这个悬念我们点开create的方法,走进Retrofit类当中,点开源码发现我们来到了Retrofit.java的第130行代码如下:
public <T> T create(final Class<T> service) {
//做一些安全判断,判断是否为接口,不是接口java原生的动态代理会报错
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//create其实就是通过Java的动态代理将接口中定义的方法转给了InvocationHandler的invoke方法
//在通过loadServiceMethod调用invoke,来发起网络请求(下篇文章会讲)
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.
//如果该方法是Object自带的方法,那么我们直接反射出来这些方法就可以了
//比如说是.equest() 、 toString()
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// .isDefaultMethod是Java8的特性
//它的意思是接口中定义的方法,因为java8支持了接口定义默认方法(default)这一特性
//也就是说,这里的if是判断上述特性,如果是就直接调用
//如果不是,就使用loadServiceMethod来获取方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//返回了 封装了请求参数的一个接口,它知道怎么发起网络请求
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
我们可以看到,这里使用了Proxy.newProxyInstance 典型的动态代理,今天解析的重点就是这里,我们点开newProxyInstance 看看它到底是怎么将接口进行代理,生成接口的代理类吧,点开后我们来到Proxy.java的719行
//newProxyInstance传入了ClassLoader 还有接口,我们可以想象得到
//他是通过ClassLoader来生成代理类的。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
...
/*
* Look up or generate the designated proxy class.
具体实现类代理的方法 getProxyClass0
*/
Class<?> cl = getProxyClass0(loader, intfs);
return cons.newInstance(new Object[]{h});
...
}
然后我们点开getProxyClass0来进一步探寻真正实现了代理的方法,点开后来到了Proxy的410行,我们看到了如下的代码:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
在这里,我们可以看到getProxyClass0返回了ProxyClassCache.get ,我们思考一下,也就是说我们的Class是从proxyClassCache里获取到的,距离真相并不遥远,我们继续往下点开ProxyClassCache我们可以看到proxyClassCache其实是一个 WeakCache,而WeakCache其实是ConcurrentMap,这里就不过多说明了,我们点开proxyClassCache后来到Proxy的239行
//注意我们这里的第二个参数ProxyClassFactory
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
是的,这个ProxyClassFactory就是我们的代理类的创造类了,距离真想只有一步之遥,我们继续点进ProxyClassFactory 为了大家方便理解,我这里将一些异常处理等非关键代码进行了简化处理,大家可以对照源码找到相应的代码来加深大家的理解。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
//生成的代理类的名字$proxy
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
//这里我也没看懂,应该是生成的第几个代理类
//这样,我们生成的代理类名字就是com.sun.proxy.$proxy0
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
//这里将我们的类名设置上去
interfaceClass = Class.forName(intf.getName(), false, loader);
}
//初始化包名
String proxyPkg = null; // package to define proxy class in
//设置类的Modifier 我们的代理类为public final的类型
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
//将方法设置为final的静态方法
accessFlags = Modifier.FINAL;
//获取接口名
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
//包名赋值
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
//设置代理类名 也就是com.sun.proxy.$proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
构建我们的代理类,这里返回byte数组也就是字节码
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
//通过defineClass0使用我们的classLoader将数组构建成真正的class
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
以上就是Retrofit的接口代理类实现的简要流程了,大家是不是还有些略有发懵?不要紧,我们可以自己实现ProxyGenerator.generateProxyClass方法,生成byte[]然后通过IO流写出一个class文件,你会发现这正是我们接口的代理类,来加深我们对java动态代理的理解,最后return的defineClass0便是我们一开始构造出的GitHub.class啦,本文只是简要的概述了动态代理的流程,Retrofit当然还做了很多东西,本文并没有讲到,这个并不是作为简要解析的重点,重点是让大家用短暂的时间理解着去看懂整个流程,而非细枝末节。
最后感谢您看完本篇文章。
网友评论