JDK8编译代码运行在OpenJDK17时Tomcat启动报SunJCE访问错误如何解决?
问题根因说明
你此前在maven-compiler-plugin中添加的--add-exports参数仅作用于编译阶段,Java 9+引入的模块系统访问限制在运行阶段仍然生效,因此启动时依旧触发访问异常。
可行解决方案
方案1:添加运行时JVM参数(临时兼容方案)
你需要在Tomcat的JVM启动参数中添加相同的导出规则,根据部署场景操作如下:
- IDE本地启动Tomcat:打开Tomcat运行配置,在VM选项/VM arguments栏添加参数:
--add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED - Linux服务器部署Tomcat:编辑
bin/catalina.sh文件,在文件开头添加配置:
JAVA_OPTS="$JAVA_OPTS --add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED"
- Windows服务器部署Tomcat:编辑
bin/catalina.bat文件,在文件开头添加配置:
set JAVA_OPTS=%JAVA_OPTS% --add-exports=java.base/com.sun.crypto.provider=ALL-UNNAMED
修改后重启Tomcat即可解决运行时报错问题。
方案2:优化代码避免访问JDK内部API(推荐治本方案)
com.sun.crypto.provider.SunJCE属于JDK内部非公开API,本身就不推荐直接引用,你可以通过以下方式避免直接实例化该类,完全避开模块访问限制:
// 先判断SunJCE是否已经注册,未注册再动态添加 Provider sunJceProvider = Security.getProvider("SunJCE"); if (sunJceProvider == null) { // Oracle/OpenJDK默认都会内置该Provider,仅特殊场景需要手动注册 sunJceProvider = (Provider) Class.forName("com.sun.crypto.provider.SunJCE").newInstance(); Security.addProvider(sunJceProvider); }
该方案无需修改任何编译、运行参数,也兼容JDK 8到JDK 17+所有版本,不会受后续JDK版本升级影响。
方案3:反射绕过访问限制(仅当无法修改JVM参数、也无法重构代码时使用)
如果业务代码无法重构,也没有权限修改Tomcat启动参数,可以通过反射关闭构造方法的访问检查来实例化:
Class<?> sunJceClazz = Class.forName("com.sun.crypto.provider.SunJCE"); Constructor<?> constructor = sunJceClazz.getDeclaredConstructor(); constructor.setAccessible(true); Provider sunJceProvider = (Provider) constructor.newInstance(); Security.addProvider(sunJceProvider);
内容的提问来源于stack exchange,提问作者Rahman
相关产品推荐
相关产品推荐

