最近在用Ruoyi框架开发项目时,遇到一个典型问题:本地引入的JAR包在开发调试时一切正常,但执行maven package生成部署包时,这些依赖就像变魔术一样消失了。相信不少朋友都踩过这个坑——明明在pom.xml里用<systemPath>指定了JAR路径,运行时也不报错,为什么最终打包会漏掉这些依赖?
以我最近的项目为例,需要在系统模块引入一个第三方签章工具包(usign-util-1.1.jar)。按照常规做法,我在pom.xml配置了如下依赖:
xml复制<dependency>
<groupId>com.usign</groupId>
<artifactId>usign-util</artifactId>
<version>1.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/usign-util-1.1.jar</systemPath>
</dependency>
开发阶段完全没问题,但打包部署后服务直接报ClassNotFoundException。打开生成的war包一看,lib目录下果然没有这个JAR文件。这其实是Spring Boot Maven插件默认行为:system作用域的依赖默认不会被打包。这种设计原本是为了避免将系统环境相关的依赖混入应用包,但在使用本地JAR时就成了拦路虎。
在找到正确解法前,我先尝试了网上常见的几种方案,结果全是坑。这里分享出来帮大家避雷:
有些教程建议在maven-compiler-plugin中添加extdirs配置:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<compilerArguments>
<extdirs>${project.basedir}/lib/usign-util-1.1.jar</extdirs>
</compilerArguments>
</configuration>
</plugin>
实测发现这完全无效,还会引发警告:"should not point at files within the project directory"。因为这个配置本意是指定扩展类库目录,而不是单个JAR文件。
另一种流行方案是通过maven-install-plugin将JAR安装到本地仓库:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<phase>clean</phase>
<configuration>
<file>${basedir}/lib/usign-util-1.1.jar</file>
<groupId>com.usign</groupId>
<artifactId>usign-util</artifactId>
<version>1.1</version>
</configuration>
<goals>
<goal>install-file</goal>
</goals>
</execution>
</executions>
</plugin>
这个方案理论上可行,但存在严重缺陷:
<scope>和<systemPath>,导致开发环境直接报错经过反复试验,最终解决方案其实非常简单——在spring-boot-maven-plugin中启用includeSystemScope。具体操作分三步:
ruoyi-system/src/main/resources/lib)在需要打包的模块(通常是admin模块)的pom.xml中,找到spring-boot-maven-plugin配置,添加<includeSystemScope>true</includeSystemScope>:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
结合Ruoyi框架特点,建议使用如下完整配置:
xml复制<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.6.3</version>
<configuration>
<fork>true</fork>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
Spring Boot Maven插件在打包时默认会过滤掉system作用域的依赖,这是为了防止将系统环境相关的JAR(如JDK工具包)打包进应用。通过设置includeSystemScope=true,我们告诉插件:"这些system范围的JAR是我们主动引入的,请保留它们"。
在Ruoyi这类多模块项目中,需要特别注意:
不同版本的Spring Boot Maven插件行为略有差异:
虽然includeSystemScope是最佳方案,但其他方法也有适用场景:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| includeSystemScope | 配置简单,不影响开发 | 需要了解插件参数 | 大多数本地JAR场景 |
| maven-install-plugin | 符合Maven规范 | 污染本地仓库,多环境部署复杂 | 需要发布到仓库的JAR |
| 手动复制到target | 最直接 | 不优雅,容易遗漏 | 快速调试临时方案 |
检查步骤:
mvn clean package确保全新构建可能原因:
如果同时使用maven-assembly-plugin等工具,可能需要额外配置:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
经过多个项目实践,我总结出以下经验:
记得第一次遇到这个问题时,我花了整整一天时间排查。现在回头看,解决方案其实很简单,但如果没有理解背后的原理,下次遇到类似问题可能还会踩坑。技术文档的质量参差不齐,关键是要学会验证和思考——这也是我写下这篇实战指南的初衷。