迁移至JDK9后出现java.lang.NoClassDefFoundError运行时错误求助
解决JDK9迁移后运行时
java.lang.NoClassDefFoundError: javax/xml/ws/Service的问题 这个问题我之前帮团队排查过好几次,核心原因是JDK9开始的模块化机制对Java EE相关API的处理变化——虽然你在module-info里声明了依赖,但JDK9默认不会在运行时加载这些被标记为deprecated的Java EE模块,而编译阶段JDK仍然会提供这些类的定义,所以才会出现「编译过、运行炸」的情况。
下面是几个靠谱的解决方案,按推荐程度排序:
方案1:切换到官方维护的外部JAX-WS依赖(推荐)
JDK9之后,Java EE相关模块(包括JAX-WS)被移出JDK,交给Eclipse基金会维护,所以最好直接用外部依赖替代JDK自带的实现:
- 在你的
pom.xml中添加完整的JAX-WS依赖:
<!-- JAX-WS API --> <dependency> <groupId>javax.xml.ws</groupId> <artifactId>jaxws-api</artifactId> <version>2.3.1</version> </dependency> <!-- JAX-WS 运行时实现 --> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-rt</artifactId> <version>2.3.5</version> <scope>runtime</scope> </dependency>
- 修改
module-info.java,替换原来的requires java.xml.ws;为:
module CXFPExGenCaller { requires java.xml; requires java.logging; requires java.xml.bind; // 替换成外部API模块 requires jaxws.api; // 如果代码直接用到了运行时实现类,还要加这个 requires com.sun.xml.ws.rt; exports ......; }
这样做的好处是彻底脱离JDK自带的废弃模块,后续升级JDK(比如到11+)也不会再出问题。
方案2:运行时手动添加模块参数(临时过渡用)
如果只是临时过渡不想换依赖,可以在运行时加上JVM参数,强制加载java.xml.ws模块:
- 直接用java命令运行时:
java --add-modules java.xml.ws -jar your-app.jar
- 如果用Maven exec插件运行,在插件配置里加参数:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <configuration> <mainClass>your.main.Class</mainClass> <arguments> <argument>--add-modules</argument> <argument>java.xml.ws</argument> </arguments> </configuration> </plugin>
注意:这个方案只适合JDK9/JDK10,JDK11已经完全移除了这些模块,到时候还是得换成方案1。
补充:为什么编译没问题?
JDK9在编译阶段仍然保留了Java EE模块的类定义,所以你的module-info.java里声明requires java.xml.ws;后,编译器能找到对应的类;但运行时JDK默认不会加载这些被标记为「待移除」的模块,所以就抛出了NoClassDefFoundError。
内容的提问来源于stack exchange,提问作者OPMendeavor
相关产品推荐
相关产品推荐

