APT技术中的SPI 机制,与javac对其的运用

SPI:Service Provider Interface

是一种服务发现机制。他通过在classPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。

//SPI机制
//对象初始化
ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);
Iterator<SPIService> iterator = load.iterator();

通过服务加载器,加载SPIservice服务,并且得到所有服务的实现类,进行加载启动。

加载的服务所在的路径是固定的。在所有过程项目同级目录新建一个resources,SPIservice文件的路径也要跟包名一致。

SpiService 内部就是指的需要加载的服务实现类名

而底层的加载流程是通过反射。

注解处理器SPI的运用

这里介绍SPI机制,是因为我们APT技术中运用到了,比如我们的在写注解处理器的时候,会在处理器中添加google 的AudoService的注解进行注册。

 注册之后,在编译阶段就能找到注解处理器类,并且执行process()方法。

如果我们不去添加AudoService注解,使用我们上面介绍的SPI技术同样可以去完成相关效果。

 

 源码的原理解析

跟踪ServiceLoader.load()方法看源码

 

 

 provider就是承载所有实现类的容器。

 看名字懒加载迭代器。然后对迭代器进行遍历执行。大概就是下面的逻辑

 当然这里execute()方法是我们接口类自己定义的。

而源码中的LazyIterator 的迭代逻辑如下:

 

 得到我们指定的resources下面SPIservice文件后进行内容的读取。io的读取把文件中的内容一行一行的读出来,然后进行反射得到class文件放入到provider容器中。

 这种spi的机制,对解耦十分有作用。

javac上SPI的运用处理

接下来看我们javac是如何对注解处理器处理的。

首先看javac的源码,首先定位到 Main.java类的main()

 

 执行到另外一个路径下的Main类,得到compiler。

继续定位到对应路径main类,compiler方法

 最终其实现类是JavaCompiler类,跟踪JavaCompiler类,可以找到

 可以看到processors其实就是Processor集合的迭代器。

compile内部对注解处理器的处理:

 

 这个红框的代码是不是很眼熟,这就是我们在一开始介绍SPI使用的时候自己写的代码。所有可以看到javac 也运用到了spi机制。

关于注解处理器的几个问题。

 1.process是怎么回调的   

2.调用的次数是怎么决定的 和是否有生成文件有关系

3.返回值有什么用? 注解是否往下传递 true表示不传递set

A1 已经在上面回答过来 通过spi 机制

A2 

我们知道process方法是用来处理注解的,但是如果生成的代码中又产生了注解呢,所以这里的process不仅仅会处理一次,而是又while循环的逻辑,直到没有注解全部被处理结束。具体的次数也不是固定的。

A3 

返回值指的process方法中的set参数是否继续往下传递。默认都需要返回false,如果返回的true会导致我们处理的所以注解集合set传递中断。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值