Lombok 执行路径
Javac:作为注解处理器启动
使用 javac
(以及 netbeans、maven、gradle 和大多数其他构建系统),lombok 作为注解处理器运行。
Lombok 在类路径上,并且 javac
将加载类路径上找到的每个 META-INF/services/javax.annotation.processing.Processor
文件,读取每一行并加载该类,然后将其作为注解处理器执行。lombok.jar
包含此文件,其中列出了 lombok.launch.AnnotationProcessorHider$AnnotationProcessor
作为入口。
这个类实际上是不可见的(它是公共的,但它的外部类 (AnnotationProcessorHider
) 是包私有的,这使得它对于 java 语言是不可见的),但是,为了 java-the-VM 的目的,它被认为是可见的,因此它将运行。这个复杂的技巧用于确保任何在类路径上使用 lombok 进行开发的人都不会将 lombok 的类或 lombok 的依赖项注入到他们的“命名空间”中(例如,如果您将 lombok 添加到您的项目中,您的 IDE 将不会开始为自动完成对话框建议 lombok 类)。
lombok.launch.AnnotationProcessorHider$AnnotationProcessor
类由 javac
加载、实例化,并调用其 init()
方法。这个类启动了 lombok 的 ShadowClassLoader
;它找到它所在的 jar 文件,然后将开始从这个 jar 文件加载类。它不像普通的加载器那样查找以 .class
结尾的文件,而是查找以 .SCL.lombok
结尾的文件(这也是为了将 lombok 的类从 IDE 等隐藏起来)。通过这个类加载器,启动了真正的注解处理器,即 lombok.core.AnnotationProcessor
类。
lombok.core.AnnotationProcessor
也是一个委托处理器。它可以根据 lombok 自身所处的环境委托给 2 个子处理器之一:如果是 javac,则使用 lombok.javac.apt.LombokProcessor
类(如果使用 plexus 编译器框架,这在使用 javac 编译时可能会发生,则会运行一些额外的代码来将 lombok 补丁到其模块化类加载架构中)。如果是 ecj(eclipse 的编译器,这意味着我们要么在 eclipse 内部运行,要么作为 ecj 的注解处理器被调用,即独立的 eclipse 编译器),则会向编译过程中注入错误/警告,以告知用户他们应该使用不同的参数来在 eclipse/ecj 中使用 lombok。
lombok.javac.apt.LombokProcessor
是“真正的”注解处理器,它负责转换您的代码。
代码转换从根本上来说是一个循环概念:要生成一些代码,您需要了解代码(例如,其中有哪些注解),但是当您生成新代码时,解释它意味着我们重新开始。这同样适用于 lombok 本身:lombok 的某些转换会添加方法,这些方法随后会对其他 lombok 转换产生影响。因此,lombok 将处理程序划分为“级别”。执行最高级别的所有处理程序,然后强制进行新的注解轮次(这将生成的内容集成到符号表等中),然后再执行下一级别的处理程序。这些级别通过 @HandlerPriority
注解指示。您通过生成文件来强制 javac 运行另一轮。我们实际上不想生成任何文件,因此我们生成一个虚拟文件并修补 javac filer 以实际上不将 lombok 生成的虚拟文件保存到任何地方。应用实际 lombok 转换的各种 HandleX
类存储在 HandlerLibrary
中,后者使用 SPI 来发现处理类。
Eclipse/ECJ:作为代理启动
使用 ecj
和 eclipse
,lombok 作为“代理”启动。这有点像调试器:它让 lombok 在 JVM 实际加载这些类之前检查原始类字节码,并且 lombok 将修改此代码以确保 ecj/eclipse 在编译过程中包含 lombok。
类的修补由 src/eclipseAgent
源代码目录中的代码完成。请注意,修补代码必须修补 equinox,即 eclipse 模块系统,以确保 lombok 和 java 编译模块(在 eclipse 术语中为“JDT”模块)可以相互看到。
应用了许多针对问题的临时修复(例如,eclipse 的代码格式化功能需要一些战术性的字节码补丁,以确保它不会搞乱格式化源),但注入到 ecj/eclipse 中的主要“将 lombok 作为编译过程的一部分运行”钩子指向了 lombok.eclipse.TransformEclipseAST
类,这可以被认为是入口点。除非您想弄乱 lombok 如何加载到 eclipse/ecj 中,否则从这里开始。
每个 HandleX
类都通过 SPI 发现,lombok 将根据需要调用处理类。处理类查找 lombok 注解并应用所需的转换。处理程序位于 src/core
源代码目录的 lombok.eclipse.handlers
包中。
VSCode 和 IntelliJ:作为插件启动
Lombok 在这两个 IDE 中的支持由这些 IDE 的插件负责。