Spring Boot Jar运行时--add-opens无法识别依赖模块的解决方案咨询
问题根源
Spring Boot打包生成的Fat Jar会把所有依赖包放在BOOT-INF/lib目录下,JVM默认会把这些依赖当作类路径资源加载,而非模块化Jar。这就导致直接使用--add-opens <依赖模块>/<包>=<你的模块>时,JVM找不到对应的依赖模块——因为它根本没被当作模块加载。而IDE中是直接通过classpath加载所有依赖,所以不会有这个问题。
解决方案
1. 手动启动时用--patch-module挂载依赖模块
如果你的依赖是模块化Jar(包含module-info.java),先通过--patch-module把依赖Jar挂载到对应的模块上,再执行--add-opens:
java --patch-module <依赖模块名>=BOOT-INF/lib/<依赖Jar文件名> --add-opens <依赖模块名>/<要开放的包>=<你的应用模块名> -jar <你的应用Jar>
举个例子,假设依赖模块名为com.example.utils,Jar文件是utils-2.0.jar,要开放com.example.utils.internal包给你的应用模块com.your.app:
java --patch-module com.example.utils=BOOT-INF/lib/utils-2.0.jar --add-opens com.example.utils/com.example.utils.internal=com.your.app -jar my-app.jar
如何确认依赖的模块名?可以执行
jar --describe-module -f BOOT-INF/lib/<依赖Jar文件名>查看输出。
如果依赖是非模块化Jar(没有module-info.java),这类类属于ALL-UNNAMED模块,直接开放给无名模块即可:
java --add-opens <JDK模块>/<包>=ALL-UNNAMED -jar <你的应用Jar>
比如开放java.base/java.lang包:
java --add-opens java.base/java.lang=ALL-UNNAMED -jar my-app.jar
2. 嵌入参数到Spring Boot Maven插件配置
不想每次启动手动输入参数?可以修改spring-boot-maven-plugin的配置,把JVM参数嵌入到Jar的启动配置中,打包后启动时会自动生效:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 模块化依赖的情况 --> <jvmArguments> --patch-module com.example.utils=BOOT-INF/lib/utils-2.0.jar --add-opens com.example.utils/com.example.utils.internal=com.your.app </jvmArguments> <!-- 非模块化依赖的情况,替换上面的jvmArguments内容 --> <!-- <jvmArguments> --add-opens java.base/java.lang=ALL-UNNAMED </jvmArguments> --> </configuration> </plugin>
注意:确保BOOT-INF/lib下的依赖Jar文件名和版本完全匹配,避免路径错误。
3. 额外提示
如果你的应用本身是模块化的(有module-info.java),要确保module-info.java中已经声明了对依赖模块的requires,否则即使挂载了模块也可能无法正常访问。
内容的提问来源于stack exchange,提问作者Kamil Wysocki

