1. 从一次真实的编译报错说起那天下午我正美滋滋地把一个老项目的JDK从1.8升级到17想着体验一下新版本带来的性能提升和新特性。项目是用Maven管理的改完pom.xml里的JDK版本信心满满地敲下mvn clean compile。结果熟悉的构建成功提示没等来等来的是一大段刺眼的红色错误日志。核心错误信息长这样[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project my-project: Fatal error compiling: java.lang.IllegalAccessError: class lombok.javac.apt.LombokProcessor (in unnamed module 0x7d41aefd) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module 0x7d41aefd相信很多从JDK 8升级上来的朋友都见过这个“老朋友”。这错误信息乍一看挺唬人的又是IllegalAccessError又是模块module不导出export的。简单翻译一下就是你项目里用的Lombok版本太老了它内部的一个处理器LombokProcessor试图去访问JDK编译器模块jdk.compiler里的一个类JavacProcessingEnvironment但是新版本的JDK模块系统把这个访问路径给封住了不允许匿名模块这么干。所以编译过程直接崩了。Lombok是什么它是一个Java库通过注解的方式让你在写实体类、配置类时不用再手动敲那一大堆getter、setter、toString、equals和hashCode方法。比如你写个Data注解在类上编译时Lombok就自动帮你生成了这些方法。它极大地提升了开发效率让代码变得非常简洁。但是它的工作原理决定了它必须和Java编译器javac“深度交流”。它是在编译期间通过Java的注解处理器Annotation Processor机制修改和增强你的抽象语法树AST。这种“深度交流”就让它对JDK的内部API产生了依赖。在JDK 8及之前这些内部API是相对开放的。但从JDK 9引入模块化系统JPMS开始这些内部API被严格封装了起来访问规则变了。老版本的Lombok不知道新规则还想按老路子走自然就被拒之门外报出上面的错误。所以这个问题的本质是Lombok版本与JDK版本不兼容。你的Lombok版本太旧不认识新JDK的“门禁系统”。解决思路也就很清晰了要么把Lombok升级到一个认识新“门禁系统”的版本要么告诉新JDK对这位“老访客”网开一面临时方案。接下来我们就围绕这两个核心思路一步步拆解解决方案。2. 诊断与排查确认你的“病因”遇到报错先别慌也别急着乱改版本。正确的第一步是精准定位问题。我们需要搞清楚两件事第一我当前用的到底是哪个版本的Lombok第二这个版本到底支不支持我现在的JDK首先查看项目中的Lombok版本。大多数Java项目都是通过Maven或Gradle来管理依赖的。Maven项目打开你的pom.xml文件在dependencies部分寻找lombok的依赖声明。它通常长这样dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.8/version !-- 关键看这里 -- scopeprovided/scope /dependency记下这个version标签里的数字比如例子里的1.18.8。Gradle项目打开build.gradle文件在dependencies块里找类似这样的配置compileOnly org.projectlombok:lombok:1.18.8 annotationProcessor org.projectlombok:lombok:1.18.8同样版本号在冒号后面。其次也是更重要的一步查询版本兼容性。你不能凭感觉猜哪个版本支持JDK 17。最权威的信息来源是Lombok官网的变更日志Changelog页面。我直接给你地址https://projectlombok.org/changelog。这个页面记录了每个Lombok版本的详细更新内容其中非常重要的一项就是“Base Java version supported”也就是基础支持的Java版本。打开这个页面你可以看到类似下面的列表这里我截取关键部分说明Lombok 1.18.30 (Jan 31, 2023): Base Java version supported: 11Lombok 1.18.28 (Dec 13, 2022): Base Java version supported: 11Lombok 1.18.26 (Oct 24, 2022): Base Java version supported: 11Lombok 1.18.24 (May 31, 2022): Base Java version supported: 11Lombok 1.18.22 (Feb 23, 2022): Base Java version supported: 11Lombok 1.18.20 (Oct 5, 2020): Base Java version supported: 1.8 (也就是JDK 8)看到规律了吗从1.18.22版本开始Lombok的“Base Java version supported”就变成了11。这意味着从这个版本起Lombok开始为JDK 9及以上的模块化环境提供正式支持。而1.18.20及更早的版本其基础支持版本是1.8它们在JDK 9的环境下运行属于“兼容模式”很容易遇到我们开头的模块访问错误。所以诊断结论很简单如果你的JDK版本是9及以上特别是11、17、21这些LTS版本那么你的Lombok版本至少需要升级到1.18.22或更高。像开头例子中的1.18.8是铁定不兼容JDK 17的。3. 根治方案升级Lombok版本确诊了“病因”治疗就很简单了把Lombok升级到兼容的版本。这是最推荐、最一劳永逸的解决方案。第一步选择合适的新版本。我个人的建议是直接使用当前可用的最新稳定版。你可以回到https://projectlombok.org/changelog页面看最顶上的那个版本。比如现在是1.18.30你就用1.18.30。使用最新版可以确保你获得所有已知问题的修复和最好的兼容性。不用担心Lombok的版本迭代非常注重向后兼容升级新版本几乎不会对你的现有代码逻辑产生任何影响。第二步修改项目依赖配置。Maven项目将pom.xml中Lombok依赖的version改为新版本例如dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version !-- 升级到最新稳定版 -- scopeprovided/scope /dependencyGradle项目修改build.gradle中两处如果有的话的版本号compileOnly org.projectlombok:lombok:1.18.30 annotationProcessor org.projectlombok:lombok:1.18.30第三步同步依赖并清理构建。改完配置后需要让构建工具重新下载新版本的Lombok。对于Maven可以执行mvn clean compile或者在你IDE的Maven面板里点击刷新按钮。对于Gradle可以执行./gradlew clean build或者在IDE里刷新Gradle项目。第四步验证IDE支持关键。这一点很多新手会忽略导致在命令行能编译但在IDE里代码依然报红。因为Lombok需要在IDE中安装插件并启用注解处理。以最常用的IntelliJ IDEA为例确保安装了Lombok插件打开IDEA的Settings (Windows/Linux) 或 Preferences (macOS)进入Plugins搜索“Lombok”确认已安装并启用。启用注解处理在Settings/Preferences中找到Build, Execution, Deployment-Compiler-Annotation Processors。勾选Enable annotation processing。重启IDEA并重建项目有时候更改需要重启IDE才能完全生效。重启后可以执行File-Invalidate Caches and Restart...来清除缓存并重启这是解决IDE各种灵异问题的“万能钥匙”。完成以上四步再次运行编译命令那个令人头疼的IllegalAccessError应该就消失了。你的项目已经可以在高版本JDK下顺畅使用Lombok了。4. 临时缓解方案添加JVM参数在某些特殊情况下你可能暂时无法升级Lombok版本。比如项目依赖的某个第三方库强制锁定了某个旧版Lombok或者你需要快速验证一个猜想不想动项目配置。这时候我们可以用一个“临时通行证”方案通过添加JVM参数让JDK模块系统对特定的内部包开放访问。这个方案的核心是使用--add-exports这个JVM参数。它的作用是告诉模块系统“请允许A模块的某个包被B模块访问”。在我们这个场景里A模块是jdk.compilerJDK编译器模块。某个包是com.sun.tools.javac.processingLombok处理器要访问的包。B模块是ALL-UNNAMED所有未命名的模块即我们传统的classpath上的所有类包括Lombok。所以完整的参数就是--add-exports jdk.compiler/com.sun.tools.javac.processingALL-UNNAMED如何在不同的构建工具中使用这个参数1. 在Maven中配置你需要配置Maven编译插件maven-compiler-plugin将参数传递给编译器。在你的pom.xml的build-plugins部分找到或添加maven-compiler-plugin的配置plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-compiler-plugin/artifactId version3.11.0/version !-- 建议使用较新版本 -- configuration source17/source !-- 你的JDK源码版本 -- target17/target !-- 你的目标字节码版本 -- compilerArgs arg--add-exports/arg argjdk.compiler/com.sun.tools.javac.processingALL-UNNAMED/arg !-- 如果还有其他类似访问错误可能需要添加多个 --add-exports 参数 -- /compilerArgs /configuration /plugin2. 在Gradle中配置在build.gradle文件中配置compileJava任务的选项tasks.withType(JavaCompile) { options.compilerArgs [--add-exports, jdk.compiler/com.sun.tools.javac.processingALL-UNNAMED] }3. 在IDE中配置以IntelliJ IDEA为例有时候你需要在IDE内部运行或调试时也生效。打开Run/Debug Configurations对话框。选择你的应用配置如Spring Boot主类。在Modify options下拉菜单中找到并选择Add VM options。在出现的VM options输入框中添加--add-exports jdk.compiler/com.sun.tools.javac.processingALL-UNNAMED重要提醒这个方案只是一个临时绕过问题的办法相当于给旧版Lombok发了一张临时通行证。它并没有解决Lombok本身与新版JDK不兼容的根本问题。长期来看它存在风险稳定性风险依赖内部API本身就不稳定未来JDK版本可能移除或修改这些API导致你的参数失效。安全风险过度开放内部API可能带来潜在的安全隐患。可维护性差你需要记住在每个需要编译、运行的地方都加上这个参数包括CI/CD流水线增加了配置的复杂性。因此强烈建议仅将此方案作为短期应急措施并尽快安排升级Lombok版本。5. 深入理解与避坑指南解决了眼前的报错我们不妨再深入一点理解背后的原理这样以后遇到类似问题就能举一反三。JDK 9引入的模块化系统Project Jigsaw是Java平台的一次重大架构升级。它把JDK自身拆分成了一个个的模块java.base,jdk.compiler等每个模块必须明确声明它导出exports哪些包给其他模块以及需要requires哪些其他模块。在模块化之前所有类都在一个巨大的“类路径”classpath上基本上可以互相访问。模块化之后访问变成了“按需索取”没有声明exports的包外部模块是无法访问的。com.sun.tools.javac.processing这个包包含了Java编译器的注解处理相关内部API在JDK 9中默认只对jdk.compiler模块内部开放不对我们应用程序所在的“未命名模块”开放。老版本Lombok设计于模块化之前通过反射等方式直接调用这些内部API来实现功能。到了新JDK这条路被模块系统的“门卫”挡住了所以抛出IllegalAccessError。新版本Lombok1.18.22则通过以下方式适配使用标准化的、稳定的API来替代内部API如果存在的话。在无法替代时通过--add-exports参数或--add-opens用于反射访问在自身启动时声明所需的访问权限使其行为变得“合规”。常见的其他“坑”与解决方案“我升级了Lombok但IDE里还是报红说找不到getter/setter方法”这几乎100%是IDE的注解处理没有正确启用或缓存问题。请严格按照第3部分第四步操作特别是“启用注解处理”和“清理缓存重启”。对于Eclipse用户也需要确保安装了Lombok插件通常通过双击下载的lombok.jar安装。“我的项目是多模块Maven项目需要每个子模块都改版本吗”最佳实践是在父pom.xml的dependencyManagement部分统一声明Lombok的版本所有子模块引用时就不需要再写版本号了便于统一管理。!-- 父 pom.xml -- dependencyManagement dependencies dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version /dependency /dependencies /dependencyManagement !-- 子模块 pom.xml -- dependencies dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId !-- 版本由父POM管理此处无需指定 -- scopeprovided/scope /dependency /dependencies“升级后构建服务器如Jenkins上编译还是失败”检查构建服务器上的JDK版本和Maven/Gradle版本是否与本地一致。确保服务器上的构建命令也应用了更改如更新后的pom.xml或build.gradle。如果使用了临时参数方案务必在构建脚本如Maven的settings.xml全局配置或Jenkins的Job配置中也加上相应的JVM参数。“除了com.sun.tools.javac.processing还有可能遇到其他类似的包访问错误吗”有可能。如果Lombok或其他注解处理器需要访问其他内部包错误信息会变化。例如可能会是com.sun.tools.javac.code、com.sun.tools.javac.util等。解决方法是一样的要么升级依赖到兼容版本要么根据错误提示添加对应的--add-exports jdk.compiler/被拒绝的包名ALL-UNNAMED参数。6. 版本选择与未来展望面对琳琅满目的Lombok版本和JDK版本我们该如何做长期规划呢这里我分享一些个人经验。Lombok版本选择策略生产项目紧跟最新的稳定版。Lombok社区活跃每个版本修复的问题和提升的兼容性都是实打实的。使用最新版能最大程度避免未知的兼容性坑。在升级前可以在测试环境充分验证。老旧项目如果项目因历史原因暂时无法升级JDK比如停留在JDK 8那么使用Lombok1.18.20或更早的版本是没问题的。但一旦有升级JDK的计划Lombok版本必须同步纳入升级清单。查看版本支持矩阵除了官网Changelog也可以关注Lombok在GitHub仓库的Issue和Release Notes那里有更详细的兼容性讨论。JDK版本升级建议从JDK 8升级到11或17是一个重要的跨越模块化是主要挑战。建议将Lombok、Maven编译插件maven-compiler-plugin、以及所有其他注解处理器如MapStruct、QueryDSL等的版本作为一个整体进行兼容性评估和升级。一个实用的检查清单Lombok版本 1.18.22maven-compiler-plugin版本 3.8.1对JDK 9支持更好检查其他涉及注解处理的依赖如MapStruct确保其版本也支持你的目标JDK。在IDE和命令行构建中彻底清理缓存。最后我想说的是技术升级的路上总会遇到类似的兼容性问题。Lombok与JDK高版本的兼容性问题是一个典型的“生态工具适配基础平台变革”的案例。解决问题的过程不仅是改一个版本号更是理解技术栈底层变化的好机会。下次再遇到类似“cannot access class ... because module ... does not export ...”的错误你应该能会心一笑从容地打开依赖的官方兼容性列表了。记住保持核心依赖编译器、核心工具库的版本处于较新且兼容的状态是维持项目长期健康开发环境的基础。