运行时注解是在程序运行时通过反射获取注解然后处理的,编译时注解是程序在编译期间通过注解处理器处理的
用来生成模版代码
1 | kapt "com.google.dagger:hilt-compiler:2.44" |
kapt/annotationProcessor关键字依赖了一个库,javac在编译的过程中就会去这个库中找符合注解处理器规则的类。 找到这个类后就把这个类认为是一个注解处理器。 但是一个大型项目中 往往会存在许多个apt库 那么这么多个处理器它是怎么被加载出来的
Java SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制.
1.定义一个接口文件
2.写出多个该接口文件的实现
3.在 src/main/resources/ 下建立 /META-INF/services 目录, 新增一个以接口命名的文件 , 内容是要接口的实现类全路径
4.使用ServiceLoader类 来获取到这些实现的接口
写法有点像什么 aidl
相比AIDL的方式,缺点是不支持跨进程,需要在接口实现的地方自己处理。
他可以帮我们在编译的时候动态去生成这些东西
通过@AutoService
省下最麻烦的第3步
javac源码 idea中打开
comp = JavaCompiler.instance(context);
和comp.compile(fileObjects, classnames.toList(), processors);
initProcessAnnotations(processors);
procEnvImpl.setProcessors(processors);
然后进入initProcessorIterator
new ServiceIterator(processorClassLoader, log);
ServiceLoader.load(Processor.class, classLoader);
discoveredProcs = new DiscoveredProcessors(processorIterator);
然后在JavaCompiler类中继续执行 找到procEnvImpl.doProcessing
round.run(false, false);
观察注释 明确这里执行processors 内部执行discoverAndRunProcs
callProcessor(ps.processor, typeElements, renv);
这个方法内调用了process方法 传入了Set<? extends TypeElement> tes,和RoundEnvironmentround.run(true, errorStatus);
和注释// run last round