上一篇文章我们了解到:框架会在编译时动态扫描
@RouterUri
注解并生成注册UriHandl
到UriAnnotationHandler
中的代码。那这些代码在运行时如何调用呢?
先了解一下ServiceLoader
这个概念。WMRouter
中的ServiceLoader
类似于java spi
ServiceLoader
它的基本功能是:
- 保存接口与实现类的对应关系。 这个关系是一对多。
- 可以实例化一个实现类,返回给调用方使用。
那在WMRouter
中,SerciceLoader
保存的接口与实现类的关系是哪些呢? 我们看一下ServiceLoader
的初始化方法:
void doInit() {
Class.forName(“com.sankuai.waimai.router.generated.ServiceLoaderInit”).getMethod("init").invoke(null);
}
即初始化的时候反射调用了ServiceLoaderInit.init()
方法。我全局搜索了一下这个类并没有发现它的声明。
最后发现这个类是使用Gradle Transform API和ams库动态生成的。
接下来我们就来研究一下这个类是怎么生成的,先来看一下WMRouter
的gradle transform插件是如何生成ServiceLoaderInit
这个类的。
WMRouterPlugin
官方是这样描述它的作用的 : 将注解生成器生成的初始化类汇总到ServiceLoader.init
,运行时直接调用ServiceLoader.init
。 从而完成SerciceLoader
的初始化。
这里我大致描述一下这个插件的工作逻辑:
- 扫描编译生成的class文件夹或者jar包的指定目录 : com/sankuai/waimai/router/generated/service, 收集目录下的类并保存起来 (这个类其实就是
ServiceInit_xxx1
这种类) - 使用
asm
生成ServiceLoaderInit
类class文件,这个class文件调用前面扫描到的类的init