一 背景

最近在用 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>

四 参考资料

 
出自:Pippo Deployment:http://www.pippo.ro/doc/deployment.html
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的更多相关文章

  1. 项目报错java.lang.ClassNotFoundException: org.common.SessionListener

    现象:项目报错java.lang.ClassNotFoundException: org.common.SessionListener,并且myeclipse左侧Package Explorer中项目 ...

  2. maven web 项目中启动报错 Java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet

    主要原因是maven项目里面的jar包吗,没有导入到项目中 maven web 项目中启动报错 Java.lang.ClassNotFoundException: org.springframewor ...

  3. maven创建spring项目之后,启动报错java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    出错情景:maven中已经加载了spring的核心包,但是项目启动时,报错: org.apache.catalina.core.StandardContext listenerStart严重: Err ...

  4. maven创建spring项目之后,启动报错java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoade

    错误: org.apache.catalina.core.StandardContext listenerStart严重: Error configuring application listener ...

  5. maven 项目启动tomcat报错 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    maven项目启动tomcat报错: java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderLi ...

  6. 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 错误描述 ...

  7. MapReduce 程序运行报错 java.lang.ClassNotFoundException解决方法

    在创建自定义的Mapper时候,编译正确,但上传到集群执行时出现错误: 11/16/05 22:53:16 INFO mapred.JobClient: Task Id : attempt_20111 ...

  8. 已解决: idea创建并部署SpringMVC项目时 报错 java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    用IDEA创建并运行SpringMVC项目时,最初发现没有Servlet包,这个问题已在上篇解决,然而当我们尝试去运行此时的SpringMVC项目时,发现仍然有错误.ClassNotFoundExce ...

  9. 【ContextLoaderListener】Web项目启动报错java.lang.ClassNotFoundException: ContextLoaderListener

    错误原因: 进入到tomcat的部署路径.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\下检查了一下,发现工程部署后在WE ...

  10. 启动Maven项目启动报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

    tomcat在发布项目的时候没有同时发布maven依赖所添加的jar包,你需要设置一下eclipse:项目 -> 属性 -> Deployment Assembly -> Add - ...

随机推荐

  1. Blocked Billboard II

    前言 今天比赛真的状态不好(腐了一小会),导致差点爆0. 这个题解真的是在非常非常专注下写出来的,要不然真的心态崩. 刚换了域名,发现了美化脚本的bug,有点担心(汗-_-||). 题目 题目描述 奶 ...

  2. Git - 01. git config

    1. 概述 管理 git 配置文件命令 配置算是 git 的 meta 大概了解下就行 写这个的原因, 是因为 安装 的时候需要配置 用户名 和 密码 这个操作本质上, 是对属性的配置 先简单知道下操 ...

  3. deepin-wine-qq无法加载图片解决方案

    最近在qq水群讨论学术的时候发现了一个奇怪的问题:无法加载图片. 具体点是,如果图片没有被其他设备接收,并且在缓存中,图片是可以加载的,反之不可. 这东西很烦人啊,于是我就去查项目issue:http ...

  4. 谁说程序员没有时间关心女朋友的,Python 教你如何掌握女神情绪变化

    很多人都是在朋友圈装死,微博上蹦迪.微信朋友圈已经不是一个可以随意发表心情的地方了,微博才是! 所以你不要傻傻盯着女神的朋友圈发呆啦!本文教你如何用 Python 自动通知女神微博情绪变化,从今天开始 ...

  5. c# Linq List<T>去除其中重复的项

    //要去重的 list<T> listTest: var resultlist= listTest.GroupBy(p =>p.Id).Select(g => g.First( ...

  6. HDU 4825 Xor Sum(字典树)

    嗯... 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4825 这道题更明确的说是一道01字典树,如果ch[u][id^1]有值,那么就向下继续查找/ ...

  7. java中4种常用线程池

    一.线程池 线程池:说白了,就是一种线程使用模式.线程过多会带来调度开销,进而影响整体性能.而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这避免了在处理短时间任务时创建与销毁线程的代价 ...

  8. SQLite - C/C++接口 API(一)

    1.sqlite3_open(const char *filename, sqlite3 **ppDb) 该例程打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据 ...

  9. Fluent_Python_Part3函数即对象,05-1class-func,一等函数,函数即对象

    一等函数 一等函数即将函数看作一等对象.一等对象满足一下条件: 在运行时创建 能赋值给变量或数据结构中的元素 能作为参数传给函数 能作为函数的返回结果 1. 一等函数 例子1. 证明function是 ...

  10. string的一些特殊点

    无论是String还是new String最终都指向了String constant pool中,只不过是String直接指向了Stringconstant pool中.而new String是在He ...