Maven系统依赖打包


在之前的博客中详细介绍了通过 Maven 实现项目的依赖管理,以及实现工程的编译构建。

熟话说巧妇难为无米之炊,实现依赖管理的前提都是需要中央仓库或本地仓库存在对应的依赖,如果依赖不存在也只能望洋兴叹。

但这类场景在开发中却又并不少见,对于某个功能涉及的依赖包经过一顿网上冲浪,终于找到了依赖文件,但依赖并未上传中央仓库无法直接集成依赖。

1. 系统依赖

幸运的是 Maven 的依赖导入提供了本地文件的引用导入,在定义依赖时将 scope 作用域定义为 system 同时通过 systemPath 用于指定依赖文件的路径。

例如下述示例即读取 D:/repo/demo-one-1.0-SNAPSHOT.jar 目录文件作为依赖包,而非从默认配置的 Maven 仓库中检索查找。如此一来,即便某个依赖文件不存在于仓库之中,仍能正常引入工程。

<dependency>
    <groupId>xyz.ibudai</groupId>
    <artifactId>demo-one</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>system</scope>
    <systemPath>D:/repo/demo-one-1.0-SNAPSHOT.jar</systemPath>
</dependency>

2. 仓库结构

在继续下一步的介绍之前,让我们先来看一下 Maven 仓库对于依赖文件是以何种结构进行管理?

在定义一个 Maven 工程时,我们都知道 groupIdartifactIdversion 三者是必不可少,分别声明了依赖的所属、名称以及版本信息,例如下述示例所展示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xyz.ibudai</groupId>
    <artifactId>demo-one</artifactId>
    <version>1.0-SNAPSHOT</version>

</project>

那你是否又好奇这个模块又是如何存储在 Maven 仓库之中?

实际上存储结构也简单明了,打开 Maven 配置的仓库目录中,可以看到依赖的存储路径是以 groupIdartifactIdversion 三者作为目录路径存储,同时针对 groupId 中的 . 按次序拆分为多个目录。

例如上述定义的模块通过 install 命令后将生成的文件目录结构如下,而文件名默认以 <artifactId>-<version>.jar 的命名规则存在。

3. 工程编译

了解了上述概念后,让我们来看一下 Maven 又是如何对工程进行编译打包。

默认 Maven 在打包构建时并不会将模块所依赖的模块一同打包进 jar 可执行文件,而是只会打包当前工程 src/main 包路径的代码文件。因此,若需要将工程的依赖一并打包通常需要利用到 Assembly 等构建插件,在之前的博客中分享过了如何使用这里就不再重复展开。

这里就直接贴出完整的 Assembly 插件打包配置,内容如下:

<plugin>  
    <groupId>org.apache.maven.plugins</groupId>  
    <artifactId>maven-assembly-plugin</artifactId>  
    <version>3.1.0</version>  
    <configuration>  
        <finalName>${project.artifactId}-${project.version}-all</finalName>  
        <appendAssemblyId>false</appendAssemblyId>  
        <descriptorRefs>  
            <descriptorRef>jar-with-dependencies</descriptorRef>  
        </descriptorRefs>  
        <attach>false</attach>  
        <archive>  
            <manifest>  
                <!-- 替换为主类完整限定名 -->
                <mainClass>fully.qualified.MainClass</mainClass> 
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
            </manifest>   
        </archive>  
    </configuration>  
    <executions>  
        <execution>  
            <id>make-assembly</id>  
            <phase>package</phase>  
            <goals>  
                <goal>single</goal>  
            </goals>  
        </execution>  
    </executions>  
</plugin>

在工程 pom.xml 文件中添加上述配置之后执行 packge 命令即可在 target 目录下生成 xxx-all.jar 可执行文件,文件内包含了工程的源码以及所有依赖的模块。

但如果你仔细观察的话,文件的确是将依赖的模块一并打包,但是刚才提到的 scope=system 依赖却并没有出现在打包后的文件中。

是的,你并没有看错,Assembly 插件将会跳过 scope=system 依赖模块,那又该如何处理?

这里就要回到刚才介绍的依赖文件存储结构了,不仅文件的生成是基于 groupIdartifactIdversion 三者,在定义 dependencyMaven 同样也是由此为依据在仓库中检索文件。但解决方案就有了,只要根据此规则为 scope=system 依赖创建同样的目录,那即可直接引用依赖无需将作用域定义于 system

最简单的方式就是手动创建目录,但 Maven 对此提供了更方便的方式,命令模板如下:

mvn install:install-file \
  -Dfile=<path-to-file> \
  -DgroupId=<my-groupId> \
  -DartifactId=<my-artifactId> \
  -Dversion=<my-version> \
  -Dpackaging=<my-packaging> \
  -DlocalRepositoryPath=<path-to-repo>

例如之前提到 demo-one-1.0-SNAPSHOT.jar 文件,通过下述命令即可在 Maven 仓库中生成对应的结构的目录。

mvn install:install-file \
  -Dfile= \
  -DgroupId=xyz.ibudai \
  -DartifactId=demo-one \
  -Dversion=1.0-SNAPSHOT \
  -Dpackaging=jar \
  -DlocalRepositoryPath=D:/repo/demo-one-1.0-SNAPSHOT.jar

那问题也迎刃而解,此时在项目中依赖 demo-one 模块则需要通过 system 执行,和其它依赖一样引用即可。与此同时,再通过 Assembly 插件也可正常实现打包构建。

<dependency>
    <groupId>xyz.ibudai</groupId>
    <artifactId>demo-one</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

上述的方式适用于本地的项目编译构建,依赖文件在本地仓库中是生成了,但线上私服仓库中仍然不存在此依赖文件。

因此,若需要实现在线编译,同样需要通过 deploy 命令将依赖推送到私服,命令格式如下:

mvn deploy:deploy-file \
  -Dfile=<path-to-file> \
  -DgroupId=<my-groupId> \
  -DartifactId=<my-artifactId> \
  -Dversion=<my-version> \
  -Dpackaging=<my-packaging> \
  -DrepositoryId=<repository-id> \
  -Durl=<repository-url>

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录