由于nacos使用了反射,但是高版本 JDK(Java9+)引入了Java 模块化机制(JPMS),做了严格的反射权限控制,而 Nacos 2.x.x 底层依赖的 Tomcat、SpringBoot 组件还沿用了 JDK8 的反射写法,在高版本 JDK 中会触发权限拦截,直接导致启动失败。
报错信息:Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field static final boolean java.io.FileSystem.useCanonCaches accessible: module java.base does not "opens java.io" to unnamed module @2f7a2457
解决方案包括:
方案一:降级 JDK 版本到 JDK8
最简单粗暴,但是如果已经使用了更高版本JDK切换比较麻烦则不推荐。
方案二:改用Nacos 3.X.X版本
Nacos 3.x.x 需要64 bit JDK 17+,新版本跟老版本有些区别,如果仅用于学习可以使用,生产上需要另外考虑适配性。
方案三:不改 JDK 版本,修改启动脚本添加兼容参数
以Nacos 2.5.2 的windows启动cmd文件为例,添加使用反射访问JDK的模块的权限的参数,效果如下:

在set NACOS_OPTS 前面,添加如下参数
bash
rem ========== Java 17+ module opens for Tomcat 9.0.83+ ===============
set "JAVA_OPT=%JAVA_OPT% --add-opens java.base/java.io=ALL-UNNAMED"
set "JAVA_OPT=%JAVA_OPT% --add-opens java.base/java.lang=ALL-UNNAMED"
set "JAVA_OPT=%JAVA_OPT% --add-opens java.base/java.util=ALL-UNNAMED"
set "JAVA_OPT=%JAVA_OPT% --add-opens java.base/sun.nio.ch=ALL-UNNAMED"
rem ====================================================================
在最后的启动命令里,添加上刚刚添加的参数,在"%JAVA%"后面添加%JAVA_OPT%,不用添加双引号 。
bash
set COMMAND="%JAVA%" %JAVA_OPT% %NACOS_JVM_OPTS% %NACOS_OPTS% %NACOS_CONFIG_OPTS% %NACOS_LOG4J_OPTS% nacos.nacos %*
保存后正常启动即可。其他版本的启动文件可能略有区别,视情况修改。
前面加的--add-opens 是JVM 核心参数,作用是「开放模块权限 」,允许指定模块的指定包,对「未命名模块」开放反射访问权限(包括私有字段 / 私有方法)
ALL-UNNAMED :代表「所有未命名模块」,Nacos、Tomcat、SpringBoot 这些应用程序,在 JDK 模块化体系中都属于「未命名模块」,写死这个值即可。