Maven下java.lang.NoClassDefFoundError

本文转载自:http://blog.youkuaiyun.com/qqhjqs/article/details/51491516

使用maven管理web项目中jar包之间的依赖,非常的方便好用,但是有时也会出现问题

项目里用net.sf.json
使用maven配置了以下jar包

jakarta commons-lang 2.5  
jakarta commons-beanutils 1.8.0  
jakarta commons-collections 3.2.1  
jakarta commons-logging 1.1.1  
ezmorph 1.0.6

如果将以上的jar包放在非maven管理的项目里的lib下,不会出现任何问题
但是在maven下,当代码跑到
JSONObject.from(str)的时候,控制台报错,错误内容如下:

复制代码
java.lang.NoClassDefFoundError: org/apache/commons/lang/exception/NestableRuntimeException  
    at java.lang.ClassLoader.defineClass1(Native Method)  
    at java.lang.ClassLoader.defineClass(Unknown Source)  
    at java.security.SecureClassLoader.defineClass(Unknown Source)  
    at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2496)  
    at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:860)  
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1302)  
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1167)  
    at com.iquant.simulated.messaging.StrategyManageTopicListener.processMessage(StrategyManageTopicListener.java:13)  
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)  
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)  
    at java.lang.reflect.Method.invoke(Unknown Source)
复制代码

刚开始我以为是包没有下载成功,或者是版本不对,当时按着这个思路,搞了大半天,确定jar包都下载了,版本也都对。
突然想到,将字符串抽出来,在main方法里跑一下,看是否成功,结果和我想的一样,是成功的,那也就是说在web运行的过程中
"找不到相关的包"
按照这个思路走了下去各种百度各种查。

然后我去tomcate发布目录下将项目的web-inf里的lib打开
查看里面有没有包含找不到的包---没有
然后看了看pom.xml配置文件commons-lang的配置语句

<dependency>  
    <groupId>commons-lang</groupId>  
    <artifactId>commons-lang</artifactId>  
    <version>2.6</version>  
    <scope>provided</scope>  
</dependency></span>  

<scope>provided</scope> 去掉之后成功!

总结了以下,关于maven下的项目,如果出现jar包的问题,应该这样查

是否下载完整---可以将该jar包坐在的文件,删除重新下载
是否版本一致---可以全局定义一个version,下载相关使用version
是否被打包---查看tomcat文件下对应项目中的webinf-lib下有没有对应的jar包,然后在看看pom.xml中是怎样配置的

maven对jar包使用的范围有一些规定

即在jar包配置的后面添加<scope>[compile ,provided,runtime,test,system ]</scope>

 

名称解释
compile (编译范围)compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。
编译范围依赖在所有的classpath 中可用,同时它们也会被打包。
provided (已提供范围)provided 依赖只有在当JDK 或者一个容器已提供该依赖之后才使用。
例如, 如果你开发了一个web 应用,你可能在编译classpath 中需要
可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 
中包含这个Servlet API;这个Servlet API JAR 由你的应用服务器或者servlet
 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。
它们不是传递性的,也不会被打包。
runtime (运行时范围)runtime 依赖在运行和测试系统的时候需要,但在编译的时候不需要。
比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现
test (测试范围)test范围依赖 在一般的编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
system (系统范围)system范围依赖与provided 类似,但是你必须显式的提供一个对于本地系统中
JAR 文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库
的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。
如果你将一个依赖范围设置成系统范围,你必须同时提供一个 systemPath 
元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的 Maven 仓库中引用依赖)。
### Maven 编译后出现 `java.lang.NoClassDefFoundError` 的解决方案 #### 问题分析 `java.lang.NoClassDefFoundError` 是一种常见的 Java 运行时异常,通常表示 JVM 在运行期间无法找到某个类的定义。这种错误可能由多种原因引起,例如依赖项缺失、classpath 配置不正确或打包过程中未包含必要的库文件。 对于基于 Maven 构建的应用程序来说,该问题通常是由于以下原因之一造成的: - **缺少依赖**:某些第三方库在编译阶段可用但在运行时不可用。 - **作用域配置不当**:Maven 中的 `<scope>` 设置可能导致某些依赖仅限于特定环境(如测试),而不在最终构建产物中。 - **打包方式错误**:如果项目被打包成 JAR 文件,则需要确保所有依赖都被正确嵌入到可执行 JAR 中。 --- #### 解决方案 ##### 方法一:检查并修复 POM.xml 中的依赖范围 确认项目的 `pom.xml` 是否存在不必要的 `<scope>` 标签设置。默认情况下,Maven 将依赖的作用域设为 `compile`,这意味着这些依赖会在编译和运行时都可用。然而,如果设置了其他作用域(如 `provided` 或 `test`),则可能导致运行时找不到对应的类。 以下是常见作用域及其含义: - `compile`:适用于大多数场景,默认值。 - `runtime`:只在运行时加载,不会参与编译。 - `test`:仅用于单元测试。 - `provided`:假设目标环境中已提供此依赖(如 Servlet 容器中的 API)[^2]。 修正示例: ```xml <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> <!-- 如果有 scope,请移除或者改为 compile --> <!--<scope>provided</scope>--> </dependency> ``` ##### 方法二:使用 Shade 插件创建 Fat Jar 为了确保所有的依赖都能被包含在一个单独的 JAR 文件中,可以利用 Maven Shade Plugin 来生成所谓的“Fat Jar”。这种方式会将所有依赖复制到主 JAR 文件内部,从而避免因 classpath 不完整而导致的 `NoClassDefFoundError` 错误。 配置示例: ```xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.example.MainApp</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ``` 通过上述插件,可以在运行 `mvn package` 命令后得到一个完整的 JAR 文件,其中包含了所有所需的依赖项[^1]。 ##### 方法三:验证 ClassLoader 加载路径 有时即使依赖已经存在于本地仓库中,也可能因为动态加载机制未能成功解析所需资源。此时可以通过打印当前线程上下文中使用的类加载器来排查具体问题所在: 调试代码如下所示: ```java public static void main(String[] args) { System.out.println("Thread ContextClassLoader: " + Thread.currentThread().getContextClassLoader()); } ``` 此外还可以尝试手动指定启动参数 `-Djava.class.path=...` 明确告知 JVM 所需查找的位置[^3]。 --- ### 总结 针对 Maven 工程中发生的 `java.lang.NoClassDefFoundError` ,应优先审查是否存在遗漏的关键外部组件;其次调整合适的依赖管理策略比如借助 shade plugin 实现自给自足型 jar 输出形式;最后必要时候深入探究底层实现细节以便定位根本诱因。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值