1. 前言
实习做NLP任务时,在离线train获得模型bin
文件后,在部署到线上之前经常需要测试一下QPS等指标,用Java
写了测试流程,用Maven
打成jar
包之后,上传到开发机。打包是用的clean package
命令,但是传到服务器上却报main NoClassDefFoundError
错误,遇到过两次,故作记录
2. 错误原因
NoClassDefFoundError是因为Java虚拟机在编译时能找到合适的类,而在运行时不能找到合适的类导致的错误。
3. 与ClassNotFoundException的区别
两者区别还蛮大的。
NoClassDefFoundError发生在JVM在动态运行时,根据提供的类名,在classpath中需要找到对应的类进行加载,当找不到这个类时,就会发生NoClassDefFoundError错误。
ClassNotFoundException完全是由于环境的问题导致的,在编译时就会报错,相对较容易解决。
4. 问题描述
我在项目引用了外部jar包,由于jar本身不支持maven,所以在使用和打包时,将jar文件添加在lib路径里,并在pom.xml文件里显式的配置了绝对引用路径,如下:
<dependency>
<groupId>com.github.XXX</groupId>groupId>
<artifactId>XXX</artifactId>artifactId>
<version>0.1</version>version>
<scope>system</scope>scope>
<systemPath>/home/your/jar/path</systemPath>systemPath>
</dependency>dependency>
借助clean package
命令进行打包,将jar包传到服务器,运行如下命令:java -cp XXX-1.0-SNAPSHOT-jar-with-dependencies.jar:. com.XXX.FasttextClassifier
,终端提示找不到引用的外部类。
5. 解决方法
将引用的外部jar包在开发机上编辑生成jar包文件,更改运行命令为:java -cp XXX-1.0-SNAPSHOT-jar-with-dependencies.jar:my/path/to/XXX.jar:. com.XXX.FasttextClassifier
,可以运行。
感觉是打包的问题,貌似并没有把依赖的包打包进来,在开发机上运行,还需要将引用的jar包路径用-cp
命令复制到classpath路径里。
6.常见的排查原因
- 对应的class在java的
classpath
中不可用 - 你可能用jar命令运行你的程序,但类并没有在jar文件的
manifest
的classpath
属性中定义 - 可能程序的启动脚本覆盖了原来的
classpath
的环境变量 - 因为
NoClassDefFoundError
是java.lang.LinkageError
的一个子类,所以可能由于程序依赖的原生的类库不可用而导致的 - 检查日志文件中是否有
java.lang.ExceptionInInitializerError
这样的错误,NoClassDefFoundError
有可能是由于静态初始化失败导致的 - 如果你工作在J2EE的环境,有多个不同的类加载器,也可能导致
NoClassDefFoundError