• 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 中 outputFileNameMappinguseUniqueVersions 都没配置,使用默认值,使得 lib/ 下的 jar包名称 和 MANIFEST.MF 下的扫描路径 jar包名称一致(都带时间戳);

    2)而我的工程 A,不只从哪里拷贝来的配置文件,配了 outputFileNameMapping (没带时间戳)但没配置 useUniqueVersions(带时间戳)导致不一致;

    所以:这两个配置,要么都有,要么都没有,不然就会出现不一致,导致报错。

    三 解决

    我个人觉得,jar 包名称还是不带时间戳更清秀些,所以我推荐 outputFileNameMappinguseUniqueVersions 都配置上,如下:

    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 ~ : - )

  • 相关阅读:
    PL/SQL中的 not
    正则12和\1的理解
    eclipse/myeclipse注释模板的修改
    jboss修改内存
    myEclipse开发内存溢出解决办法myEclipse调整jvm内存大小 java.lang.OutOfMemoryError: PermGen space及其解决方法
    MyEclipse 启动报错:'Building workspace' has encountered a problem解决方法
    jboss 7.1.1.final 报错 set the maxParameterCount attribute on the Connector
    在 Ubuntu/Debian 下安装 PHP7.3 教程
    mariadb新安装解决远程访问以及root登录
    Docker 探索安装WordPress+Mysql8.0
  • 原文地址:https://www.cnblogs.com/southday/p/12115013.html
Copyright © 2020-2023  润新知