针对一个 Maven 的 Java 项目,我们执行 mvn deploy 命令时想要把生成的 jar 包上传到 Maven 仓库(本文将使用私有的 Nexus 仓库)中去。所要用到的插件 Maven Deploy Plugin,本文实际就是讲述如何用该插件上传 jar 包到 Maven 仓库,更多用法请参考该插件的官方文档。
本文关键性的两个配置文件是 pom.xml 和 settings.xml。前者配置仓库的地址,后者中配置用户名和密码。要确定 Maven 使用了哪个 settings.xml 文件,用 mvn -X
查看,比如下面的输出
[DEBUG] Reading global settings from /usr/local/Cellar/maven/3.8.3/libexec/conf/settings.xml
[DEBUG] Reading user settings from /Users/yanbin/.m2/settings.xml
Maven 还允许在执行 mvn 命令时用 -s 或 --settings 参数指定 settings.xml 文件,如 mvn deploy --settings settings.xml
所以对于 settings.xml 文件的修改,可修改全局的,用户的或参数 --settings 指定的。
来一个实际的应用场景,假如我们要上传 jar 包(根据是否为 SNAPSHOT 包) 到下方相应的仓库中
- https://nexus.example.com/repository/maven-releases: release 包,即版本号不是 *-SNAPSHOT
- https://nexus.example.com/repository/maven-snapshots: snapshot 包,即版本号为 *-SNAPSHOT
瞧瞧可采用的几种方式
基本的操作方式
下面是一个完整的 pom.xml 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>blog.yanbin</groupId> <artifactId>kafka-common</artifactId> <version>1.0.0-SNAPSHOT</version> <name>kafka-common</name> <distributionManagement> <repository> <id>private-release</id> <url>http://nexus.example.com/repository/maven-releases</url> </repository> <snapshotRepository> <id>private-snapshot</id> <url>http://nexus.example.com/repository/maven-snapshots</url> </snapshotRepository> </distributionManagement> </project> |
由于 version 是 1.0.0-SNAPSHOT,所以将会部署到 distributionManagement/snapshotRepository 指示的仓库中,该仓库的 id 是 private-snapshot。如果我们执行 mvn deploy,Maven 将从 settings.xml 中找到该 id 对应的用户名和密码。因此我们须在 settings.xml 文件中预先配置
假如我们修改用户的 settings.xml 文件 ~/.m2/settings.xml
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd"> <servers> <server> <id>private-snapshot</id> <username>admin</username> <password>admin123</password> </server> </servers> </settings> |
现在我们来执行 mvn deploy, 这里跳过 test 和 install 这两步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$ mvn deploy -Dmaven.test.skip -Dmaven.install.skip ...... [INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ kafka-common --- Downloading from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Downloaded from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.0 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.jar (1.9 kB at 13 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/kafka-common-1.0.0-20211114.001059-5.pom (1.2 kB at 1.9 kB/s) Downloading from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Downloaded from private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.5 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/1.0.0-SNAPSHOT/maven-metadata.xml (773 B at 4.9 kB/s) Uploading to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml Uploaded to private-snapshot: http://nexus.example.com/repository/maven-snapshots/blog/yanbin/kafka-common/maven-metadata.xml (283 B at 2.6 kB/s) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ ...... |
上传成功了,如果 version 不是 *-SNAPSHOT, 比如为 1.0.0
, 它将会上传到 id 为 private-release
仓库,在 ~/.m2/settings.xml
就要有对应 id 为 private-release
的 <server>
来配置用户和密码。
还可以其他多种传入用户名密码的方式
通过系统属性传入帐号信息
配置 ~/.m2/settings.xml
的 <server>
1 2 3 4 5 6 7 |
<servers> <server> <id>private-snapshot</id> <username>${CI_USERNAME}</username> <password>${CI_PASSWORD}</password> </server> </servers> |
mvn 命令为
$ mvn deploy -DCI_USERNAME=admin -DCI_PASSWORD=admin123
通过环境变量传入帐号信息
配置 ~/.m2/settings.xml
的 <server>
1 2 3 4 5 |
<server> <id>private-snapshot</id> <username>${env.CI_USERNAME}</username> <password>${env.CI_PASSWORD}</password> </server> |
执行 mvn 命令前必须设置相应的环境变量
$ export CI_USERNAME=admin
$ export CI_PASSWORD=admin123
$ mvn deploy
settings.xml 中全动态
我们还可以在 settings.xml 把 <server> 的 id, username 和 password 配置成全动态的,如
1 2 3 4 5 |
<server> <id>${repo.id}</id> <username>${repo.login}</username> <password>${repo.pwd}</password> </server> |
有了它以后就能以一变应万变,只要看着 pom.xml 中的 distributionManagement/*/id 下菜就行了,如
$ mvn deploy -Drepo.id=private-snapshot -Drepo.login=admin -Drepo.pwd=admin123
这种全动态的 <server> 配置放到 settings.xml 中简直是百利而无一害,就是一个万能的 <server> 配置。
配置用户名密码到 url 中
这种方式我们用不着 settings.xml
文件,测试前可把 settings.xml
文件删除。只需修改 pom.xml
文件, 给 distributionManagement 中的 <url> 中配置上用户名和密码
1 2 3 4 5 6 7 8 9 10 |
<distributionManagement> <repository> <id>private-release</id> <url>http://admin:admin123@nexus.example.com/repository/maven-releases</url> </repository> <snapshotRepository> <id>private-snapshot</id> <url>http://admin:admin123@nexus.example.com/repository/maven-snapshots</url> </snapshotRepository> </distributionManagement> |
然后执行 mvn deploy
即能成功上传 jar 包。这种配置方式肯定不安全,绝对不应该把密码放到项目文件中去的,所以千万别采用。
使用 alt*Repository 系统属性
继续往深处挖,mvn deploy:deploy 还提供对 altDeploymentRepository
, altSnapshotDeploymentRepository
, 和 altReleaseDeploymentRepository
三个属性的覆盖。这就能演绎出更精致的用法。在 pom.xml
中整个 <distributionManagement>
都不需要配置,你不想要 settings.xml
文件也没问题,只要命令
$ mvn deploy -DaltDeploymentRepository=private-snapshot::default::http://admin:admin123@nexus.example.com/repository/maven-snapshots
如果是搭配前面那个万能的 settings.xml <server> 配置,需要命令就是
$ mvn deploy -DaltDeploymentRepository=private-snapshot::default::http://nexus.example.com/repository/maven-snapshots \
-Drepo.id=private-snapshot -Drepo.login=admin -Drepo.pwd=admin123
注意 alt*Repository
的格式是 id::layout::url
, layout 为 default 就行。其他两个,altSnapshotDeploymentRepository 和 altReleaseDeploymentRepository 也能用系统属性覆盖。
-DaltDeploymentRepository 的方式给我们带来一种不用修改原有的 pom.xml 文件也能把它部署到任意仓库的便利。如果是自己管理的 Maven 项目,还是推荐在 pom.xml 中加上 <distributionManagement> 配置,这为我们使用 mvn deploy 命令更简单。
直接上传一个 jar 文件
有时候拿到的是一个别人的 jar,没有源文件,想把它直接上传到 Maven 仓库中去供其它 Java 项目享用, 这时候我们要用到的命令是 mvn deploy:deploy-file。当然登陆 nexus Web 控制台手工上传也行,本文主要讲 mvn deploy 的使用。
回顾一下用 twine 把一个 Python 的 whl 包上传到 nexus 上的方式
twine upload --repository-url=https://nexus.example.com/repository/pypi-hosted/ dist/bounded_executor-0.0.3-py3-none-any.whl
直接上传一个 jar 文件与针对 Maven 项目执行 mvn deploy
并无多大区别,唯一不同的是 Maven 项目有一个 pom.xml 文件,在其中有 groupId, artifactId, version 等的描述,而使用 mvn deploy:deploy-file
的话就要在命令中给出相同的信息。mvn deploy:deploy-file
也能用 -DpomFile
指定一个 pom.xml 文件, 如果该 jar 有传递的依赖也许是有必要用这个参数。
应用 settings.xml 的帐号信息
执行 deploy:deploy-file 依旧可以用 settings.xml 文件,配置方式与前面三种方式是一样的,帐户信息可明文配置,或从系统属性或环境变量中来。假如 jar 包文件名是 redis-common-1.0.0-SNAPSHOT.jar, ~/.m2/settings.xml
中配置的 server
1 2 3 4 5 6 7 |
<servers> <server> <id>private-snapshot</id> <username>${CI_USERNAME}</username> <password>${CI_PASSWORD}</password> </server> </servers> |
上传该 jar 包到私有仓库的命令是
mvn deploy:deploy-file -DCI_USERNAME=admin -DCI_PASSWORD=admin123 \
-DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \
-DrepositoryId=private-snapshot \
-Durl=http://nexus.example.com/repository/maven-snapshots \
-Dfile=redis-common-1.0.0-SNAPSHOT.jar
settings.xml 中配置 <server> 的 id, username, password 全部从系统属性/环境变量中来的方式也适用于此处。
无需 settings.xml 文件
也可以完全不用 settings.xml 文件,而在 mvn 命令中的 URL 中带上用户名和密码。测试下面的命令前把 ~/.m2/settings.xml
文件先删除
mvn deploy:deploy-file \
-DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \
-Durl=http://admin:admin123@nexus.example.com/repository/maven-snapshots \
-Dfile=redis-common-1.0.0-SNAPSHOT.jar
这种方式对于临时把一个 jar 包上传到私有仓库更快捷,反正是本机执行,不应有什么安全隐患。此时如果使用 settings.xml 配置了用户名和密码,那么 -Durl 中的用户名和密码将被忽略。
和任何 bash 命令一样,密码中带有特殊符号的要注意转义,比如密码是 aB!ak47%^
,在 mvn deploy:deploy-file 命令的 -Durl 写成
-Durl=http://admin:aB!ak47%^@nexus.example.com/repository/maven-snapshots
在 zsh 中将会看到
zsh: event not found: ak47
在 bash 中看到的是
bash: !ak47%^@nexus.example.com/repository/maven-snapshots: event not found
原因是感叹号 !
在 zsh 和 bash 中是唤起一个历史命令,如 !ak47
是从历史命令中查找一个以 ak47
开头的命令,没有的话就是 event not found
.
所以我们必须对感叹号进行转义,在它前头加上反斜杠,完整的 mvn deploy:deploy-file 命令是
mvn deploy:deploy-file \
-DgroupId=blog.yanbin.redis -DartifactId=redis-common -Dversion=1.0.0-SNAPSHOT -Dpackaing=jar \
-Durl=http://admin:aB\!ak47%^@nexus.example.com/repository/maven-snapshots \
-Dfile=redis-common-1.0.0-SNAPSHOT.jar
实际的密码 aB!ak47%^
被转义为 aB\!ak47%^
。
如果把这个 mvn deploy:deploy-file 命令写到一个 deploy.sh
文件中的话,转义又多余了,其中 -Durl 部分写成 -Durl=http://admin:aB!ak47%^@nexus.... ,然后用 sh deploy.sh
执行也不会有问题。
Maven effective-settings 插件
该插件能显示出 Maven 用到的 settings 信息,包括其中配置的用户名密码
$ mvn help:effective-settings -DshowPasswords=true
总结
对于 mvn deploy 或 mvn deploy:deploy-file 命令,所需要的用户名密码信息可配置到本地的 settings.xml 文件中。
如果想通过命令行传递帐号信息,在 settings.xml 加上一个全能的 <server> 配置
1 2 3 4 5 |
<server> <id>${repo.id}</id> <username>${repo.login}</username> <password>${repo.pwd}</password> </server> |
是非常有积极意义的,在 CI(如 Jenkins) 上执行时要注意屏蔽控制台输出中的密码信息。
使用 -DaltDeploymentRepository=<id::default::user:pass@url> 的方式能够在不触及任何配置的情况下把构建部署到任意仓库中
最后又要重复一下,真正要把 mvn deploy 用法写下来,不可避免的会越走越远,这就是写博客的意义,与草草了事的笔记不在一个数量极上。
链接:
- Maven Deploy to Nexus
- Maven: Deploy Artifacts to Nexus
- Guid to deploying 3rd party JARs to remote repository
- Is it possible to pass a password in Maven Deploy in the command line?
本文链接 https://yanbin.blog/mvn-deploy-file-to-maven-repository/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。