Spring Boot 项目本地运行无异常,部署到 Linux 服务器运行报错:java.lang.ClassNotFoundException
一 背景
最近在用 Springboot 开发项目 A,引了小伙伴开发的模块 B,本地起服务,运行的好好的,等部署到服务器上,一运行就报错:Caused by: java.lang.ClassNotFoundException。
注:导致该错误的原因有很多,比如:包冲突、类冲突、包不存在等,我这里只列举其中一种情况,毕竟坑了我半天的时间,我觉得有必要分享出来。
二 原因
先看一个诡异的现象吧,我用别的工程 C 引用了同样的依赖 B,部署到服务器上,运行的好好的,就我这个工程不行?细看:
1)工程 C 部署到服务器上,/app/C-service/lib 下的 jar包是:
B-api-1.0.0-20191224.024308-5.jar
B-dao-1.0.0-20191223.073120-2.jar
2)工程 C 部署到服务器上,/app/C-service/C-service.jar/META-INF/MANIFEST.MF,扫描路径是:
lib/B-api-1.0.0-20191224.024308-5.jar
lib/B-dao-1.0.0-20191223.073120-2.jar
而:
1)我的工程 A 部署到服务器上,/app/A-service/lib 下的 jar包是:
B-api-1.0.0-SNAPSHOT.jar
B-dao-1.0.0-SNAPSHOT.jar
2)我的工程 A 部署到服务器上,/app/A-service/A-service.jar/META-INF/MANIFEST.MF,扫描路径是:
lib/B-api-1.0.0-20191224.024308-5.jar
lib/B-dao-1.0.0-20191223.073120-2.jar
发现:MANIFEST.MF 中扫描的 jar 包路径和实际解压出来的 jar 包名称不一致(一个带时间戳,一个是 SNAPSHOT),所以扫描不到 jar 包,导致报错:Caused by: java.lang.ClassNotFoundException。
那么是什么原因构成了这桩惨案呢?机缘巧合:
1.我小伙伴的模块,deploy 时用的是 SNAPSHOT,如 1.0.0-SNAPSHOT,我在拉取 jar包时,拉到的是:B-api-1.0.0-20191224.024308-5.jar:
<dependency>
<groupId>com.xxx.xxx</groupId>
<artifactId>B-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
2.我的工程 A 本地可以跑,是因为那时候我没有打包 mvn clean package -Dmaven.test.skip=true,IDEA 本地运行项目时 jar 包扫描路径 和 实际拉取的 jar 包一致;当我打包后,解压出 A-service.zip 包,本地运行同样会报错;
3.问题在于工程 A 打包前后的区别,为什么打包后:MANIFEST.MF 和 A-service.zip 解压后的 lib/ 目录下的 jar包 名称不一致?
4.最后通过比较工程 C 的配置文件和 A 的配置文件,找到不同点:A工程的 assembly.xml 中多了一行:<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
<dependencySets>
<dependencySet>
<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
5.把这行去掉,问题确实解决了。但是为什么呢?拉下来的 jar 包、MANIFEST.MF 中扫描的 jar包带时间戳,总觉得不够清秀、哪里不对劲。随后我以 outputFileNameMapping 为字眼找了下相关资料,果然找到了另外一位老大哥:<useUniqueVersions>false</useUniqueVersions> ,这行配置是放在工程的 Service 模块(Application.java 启动类所在模块)的 pom.xml 中:
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>${main.class}</mainClass>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
</excludes>
</configuration>
</plugin>
6.解释:
1)<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>,作用是在你打包的时候:lib/ 下的 jar 包可以重命名,比如本来应该是 B-api-1.0.0-20191224.024308-5.jar,通过这行配置后,jar包被重命名为:B-api-1.0.0-SNAPSHOT.jar;
2)<useUniqueVersions>false</useUniqueVersions>,作用是在你生成 MANIFEST.MF 文件时,lib/ 下的 jar包如果版本是 xxx-SNAPSHOT,要不要带唯一版本时间戳,如果你配置为 false(默认为 true),那么本来应该是 B-api-1.0.0-20191224.024308-5.jar,通过这行配置后,jar包被重命名为:B-api-1.0.0-SNAPSHOT.jar;
刚好:
1)工程 C 中 outputFileNameMapping,useUniqueVersions 都没配置,使用默认值,使得 lib/ 下的 jar包名称 和 MANIFEST.MF 下的扫描路径 jar包名称一致(都带时间戳);
2)而我的工程 A,不只从哪里拷贝来的配置文件,配了 outputFileNameMapping (没带时间戳),但没配置 useUniqueVersions(带时间戳),导致不一致;
所以:这两个配置,要么都有,要么都没有,不然就会出现不一致,导致报错。
三 解决
我个人觉得,jar 包名称还是不带时间戳更清秀些,所以我推荐 outputFileNameMapping,useUniqueVersions 都配置上,如下:
1.assembly.xml 中添加配置:<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
<dependencySets>
<dependencySet>
<outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}</outputFileNameMapping>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
2.启动类 Application.java 所在模块的 pom.xml 中添加配置:<useUniqueVersions>false</useUniqueVersions>
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>${main.class}</mainClass>
<useUniqueVersions>false</useUniqueVersions>
</manifest>
</archive>
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
</excludes>
</configuration>
</plugin>
四 参考资料
Snapshot Workaround
If you are using a SNAPSHOT version of Pippo as described in the Maven section, a small workaround is necessary due to a Maven bug:
1) Add <outputFileNameMapping>${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}</outputFileNameMapping> to the dependencySet element inside assembly.xml
2) Add <useUniqueVersions>false</useUniqueVersions> to the maven-jar-plugin’s manifest section inside pom.xml
转载请注明出处哈,have a good time ~ : - )
Spring Boot 项目本地运行无异常,部署到 Linux 服务器运行报错:java.lang.ClassNotFoundException的更多相关文章
- 项目报错java.lang.ClassNotFoundException: org.common.SessionListener
现象:项目报错java.lang.ClassNotFoundException: org.common.SessionListener,并且myeclipse左侧Package Explorer中项目 ...
- maven web 项目中启动报错 Java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet
主要原因是maven项目里面的jar包吗,没有导入到项目中 maven web 项目中启动报错 Java.lang.ClassNotFoundException: org.springframewor ...
- maven创建spring项目之后,启动报错java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
出错情景:maven中已经加载了spring的核心包,但是项目启动时,报错: org.apache.catalina.core.StandardContext listenerStart严重: Err ...
- maven创建spring项目之后,启动报错java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoade
错误: org.apache.catalina.core.StandardContext listenerStart严重: Error configuring application listener ...
- maven 项目启动tomcat报错 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
maven项目启动tomcat报错: java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderLi ...
- maven web 项目中启动报错java.lang.ClassNotFoundException: org.springframework.web.util.Log4jConfigListener
环境:Groovy/Grails Tool Suite 3.1.0.RELEASE(BASED ON ECLIPSE JUNO 3.8.1).JDK1.6.Maven3.05.Tomcat6 错误描述 ...
- MapReduce 程序运行报错 java.lang.ClassNotFoundException解决方法
在创建自定义的Mapper时候,编译正确,但上传到集群执行时出现错误: 11/16/05 22:53:16 INFO mapred.JobClient: Task Id : attempt_20111 ...
- 已解决: idea创建并部署SpringMVC项目时 报错 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
用IDEA创建并运行SpringMVC项目时,最初发现没有Servlet包,这个问题已在上篇解决,然而当我们尝试去运行此时的SpringMVC项目时,发现仍然有错误.ClassNotFoundExce ...
- 【ContextLoaderListener】Web项目启动报错java.lang.ClassNotFoundException: ContextLoaderListener
错误原因: 进入到tomcat的部署路径.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\下检查了一下,发现工程部署后在WE ...
- 启动Maven项目启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
tomcat在发布项目的时候没有同时发布maven依赖所添加的jar包,你需要设置一下eclipse:项目 -> 属性 -> Deployment Assembly -> Add - ...
随机推荐
- 第二十一篇 Linux中的环境变量简单介绍
环境变量之 PATH 定义解释器搜索用户执行命令的路径 获取PATH变量的值: echo $PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/us ...
- 关于反射中如何剔除实体类中serialVersionUID字段
Field[] fields = t.getClass().getDeclaredFields(); //这里为了剔除serialVersionUID Field[] tempArr = new Fi ...
- [lua]紫猫lua教程-命令宝典-L1-01-06. 循环结构
L1[循环]01. for循环结构介绍 只是简单的说了下计数型的for循环结构 for i=1,10,1 do testlib.traceprint(i) end 注意几点: 1.上面的1和10表示循 ...
- P2023 [AHOI2009]维护序列 区间加乘模板
题意: 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式:N<=1e5(1)把数列中的一段数全部乘一个值;(2)把数列中的一段数全部加一个值;(3)询问数列中的一段数的和,由于 ...
- 使用Newtonsoft序列化对象,实现深拷贝
工作记录 深拷贝:全新创建一个对象,值与复制对象一致,两个对象互不相关,修改一个对象不会影响到另一个对象 浅拷贝:全新创建一个对象,值与复制对象一致,两个对象相关,修改一个对象影响到另一个对象 在工作 ...
- Day1 面向对象编程与Java核心类
this变量 在方法内部,可以使用一个隐含的变量this,它始终指向当前实例.如果没有命名冲突,可以省略this. 但是,如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this. 构造方 ...
- 大小端(MSB & LSB)
谈到字节序的问题,必然牵涉到两大CPU派系.那就是Motorola的PowerPC系列CPU和Intel的x86系列CPU.PowerPC系列采用big endian方式存储数据,而x86系列则采用l ...
- 爬虫 - Scrapy中间件
前提:看Scrapy架构图 不管什么Middlewares,都写在middlewares.py里面. 然后在settings.py里的DOWNLOADER_MIDDLEWARES或者SPIDER_MI ...
- C语言随笔2: rom ram 及其运行的过程
内存的分配方式 五个区 :堆区.栈区.全局区.文字常量区.程序代码区 这五个区是ram中的.或者说,堆栈段.数据段.代码段 而rom中,没有堆区和栈区,只有数据段和代码段. ram是在程序运行是的内存 ...
- JVM 初始
我们刚学习java的时候,从来没有想过new一个对象后,需要我们手动去管理过他的内存空间释放,因为我们知道java有GC垃圾回收器这哥们的存在,他会帮我们处理好一切,这就好比我是皇帝,我想在哪建个行宫 ...