Maven时间戳版本引发的未知类异常

文章首发于个人博客,欢迎访问关注:https://www.lin2j.tech

起因

今天在打包新项目到服务器运行时,项目启动失败,报的异常是 ClassNotFoundException,而项目在本地启动是没有任何问题的。

ClassNotFound

分析

不过既然是找不到类,我还是再检查了一遍引入的依赖,并且检查 lib 目录下是否有报类缺失的 jar 包。然而,对应的 jar 包确实有在 lib 包下面。

lib-folder

为了进一步了解依赖的引入关系,我将主类所在的 jar 进行解压(unzip *.jar),并检查 MANIFEST.MF 中的类路径。

MANIFEST

这时候可以发现,MANIFEST.MF 中的类路径和 lib 下的路径明显不一样了。

MANIFEST.MF 中的包名是不带时间戳的,而 lib 下的是带时间戳的,所以 JVM 在 lib 下找不到想要的 jar 包(不带时间戳的),最终报了 ClassNotFoundException。

结论

显然,现在的解决方案就是想办法让 MANIFEST.MF 中的包名和 lib 下的包名一致即可。

通过Google,我最终确定这两处包名的格式是由我的 pom.xml 以及assembly.xml 的配置决定的。

pom.xml 的配置项 useUniqueVersions 设置为 false,在打包时将不会把jar包的时间戳记录到 MANIFEST.MF 中。

而在 assembly.xml 中的 dependencySet 配置项中没有对 lib 下的 jar 包的格式进行限制。

因此导致了 MANIFEST.MF 中的包名没有时间戳,而 lib 下的包名没有改变,从而二者不同。

pom.xml 文件的关键配置

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <!-- 剔除配置文件 -->
        <excludes>
            <exclude>*.properties</exclude>
            <exclude>*.yml</exclude>
            <exclude>*.xml</exclude>
        </excludes>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- MANIFEST.MF 中 Class-Path 各个依赖加入前缀 -->
                <!--lib文件夹内容,需要 maven-dependency-plugin插件补充 -->
                <classpathPrefix>../lib</classpathPrefix>
                <!-- jar包不包含唯一版本标识 -->
                <useUniqueVersions>false</useUniqueVersions>
                <!--指定入口类 -->
                <mainClass>com.suntek.video.app.VideoWebApplication</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

assembly.xml 的关键配置

<dependencySets>
    <dependencySet>
        <outputDirectory>lib</outputDirectory>
    </dependencySet>
</dependencySets>

解决办法

解决办法是想办法让 lib 下的包名不要包含时间戳。

需要 dependencySet 下增加一项配置 outputFileNameMapping 来固定 lib 下的 jar 包名称,去掉时间戳。

修改后的 assembly.xml

<dependencySet>
    <outputFileNameMapping>
        ${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}
    </outputFileNameMapping>
    <outputDirectory>lib</outputDirectory>
</dependencySet>

再一次打包,发现 lib 下的包名称已经改变了,也能正常启动了。

lib-folder-format

最后我觉得这种方式虽然能解决这个问题,但是相对还是比较麻烦的。建议还是使用 spring-boot-maven-plugin 来打包,就不会出现这种时间戳问题。

### 如何配置 Maven 快照版本时间戳 Maven 的 `settings.xml` 文件可以用来控制快照版本的更新频率。通过设置 `<snapshots>` 元素下的 `<updatePolicy>` 属性,能够定义何时检查远程仓库中的新快照版本。 #### 设置快照更新策略 在 `${user.home}/.m2/settings.xml` 或者项目级别的 `pom.xml` 中,可以通过如下方式来配置: ```xml <repositories> <repository> <id>example-repo</id> <url>http://repo.example.com/maven2</url> <releases> <!-- 对于发布版,默认总是不检查 --> <enabled>true</enabled> <checksumPolicy>warn</checksumPolicy> <updatePolicy>never</updatePolicy> </releases> <snapshots> <!-- 对于快照版,这里指定了每小时检查一次 --> <enabled>true</enabled> <checksumPolicy>warn</checksumPolicy> <updatePolicy>hourly</updatePolicy> </snapshots> </repository> </repositories> ``` 上述配置中,对于快照版本设置了 `hourly` 更新策略,意味着每隔一小时会尝试拉取最新的快照版本[^1]。 #### 时间戳机制的工作原理 当启用快照支持并部署了一个新的构建时,该构建会被赋予一个基于当前日期和时间的时间戳名称。例如,假设有一个名为 `my-app-1.0-SNAPSHOT.jar` 的工件,在每次成功构建后实际存储的名字可能是似于 `my-app-1.0-20230918.174512-1.jar` 这样的形式。这种命名约定允许区分不同时间点上的同一快照版本的不同实例[^2]。 #### 自定义时间戳格式 默认情况下,Maven 使用 ISO 8601 标准格式化时间戳。然而,也可以自定义此行为,但这通常涉及到修改服务器端配置而非客户端侧的 `settings.xml` 文件。大多数时候,默认的行为已经足够满足需求。 #### 控制台命令指定 settings.xml 为了确保这些配置生效,可以在执行 Maven 命令时显式地指向所需的 `settings.xml` 文件路径: ```bash mvn clean install --settings /path/to/your/custom-settings.xml ``` 这使得能够在不同的环境中灵活应用各种设定而无需更改全局配置文件。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值