distributionManagement
本章是"部署与分发"主题的起点。入门教程讲解了本地仓库和私服的概念,本章解决"如何把构建产物从本地推送到远程仓库"的具体配置问题。理解distributionManagement,是团队协作中共享构件的前提。
核心机制
distributionManagement是pom.xml中专门定义远程部署目标的标签。它告诉Maven:执行mvn deploy时,应该把jar包、pom文件和附属构件(如源码包、文档包)上传到哪个远程仓库。
入门教程已经讲过,Maven的仓库体系分为本地仓库(~/.m2/repository)和远程仓库(中央仓库、私服等)。mvn install把构件放进本地仓库,仅供本机使用;mvn deploy把构件推送到远程仓库,供整个团队甚至外部用户下载。而distributionManagement就是deploy命令的"导航地图"。
distributionManagement的结构
<distributionManagement>
<!-- 发布版仓库:version不含SNAPSHOT时部署到这里 -->
<repository>
<id>feixiang-releases</id>
<name>飞翔科技发布仓库</name>
<url>http://nexus.feixiang.com/repository/maven-releases/</url>
</repository>
<!-- 快照版仓库:version含SNAPSHOT时部署到这里 -->
<snapshotRepository>
<id>feixiang-snapshots</id>
<name>飞翔科技快照仓库</name>
<url>http://nexus.feixiang.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
三个关键设计决策
为什么要分开repository和snapshotRepository? 发布版(Release)和快照版(Snapshot)的治理策略完全不同。Release一旦上传不可覆盖,保证可复现性;Snapshot允许反复覆盖,支持持续集成。物理隔离到不同仓库,是Nexus/Artifactory等私服的标准实践。
id的作用是什么?
id不是URL的别名,而是认证凭证的绑定键。settings.xml中<server>标签的id必须与这里完全匹配,Maven才能找到对应的用户名密码。同一个URL可以配多个id,对应不同的权限账号。url支持哪些协议? Maven 3.x支持
http://、https://、scp://、sftp://和file://。其中http/https最常见,对应Nexus或Artifactory;scp/sftp用于直接推送到远程服务器目录;file://用于本地文件系统测试(如共享目录模拟仓库)。
生活类比:快递发货系统
想象飞翔科技的电商仓库:
- 本地仓库(mvn install):公司楼下的自提柜。你自己把包裹放进去,只有你自己能取。
- 远程仓库(mvn deploy):全国分拨中心。你把包裹交给快递员(deploy插件),由分拨中心统一管理和分发。
- distributionManagement:你贴在包裹上的发货单,写明"发往华东分拨中心"还是"华南分拨中心"。
- repository vs snapshotRepository:普通商品走"标准物流"(Release仓库),生鲜冷链走"特快专递"(Snapshot仓库)——不同的通道、不同的处理规则。
图示
上图展示了deploy的完整链路。distributionManagement是决策分叉点:根据version是否包含SNAPSHOT,选择不同的目标仓库。无论走哪条路,都必须经过settings.xml的认证检查——没有匹配的server配置,上传会被拒绝。
完整示例
场景
飞翔科技的order-service项目开发到1.2.0版本,需要部署到公司私服。CTO大翔的要求是:
- SNAPSHOT版本自动进快照库,方便前端黄俪随时联调最新后端
- RELEASE版本进发布库,只有架构师白歌审批后才能正式发布
- 源码包和文档包必须一起部署,方便其他团队调试
完整pom.xml配置
<?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>com.feixiang</groupId>
<artifactId>order-service</artifactId>
<version>1.2.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>飞翔科技订单服务</name>
<description>订单核心服务,供商城、支付、物流模块调用</description>
<!-- 部署目标配置 -->
<distributionManagement>
<repository>
<id>feixiang-releases</id>
<name>飞翔科技Maven发布仓库</name>
<url>https://nexus.feixiang.com/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>feixiang-snapshots</id>
<name>飞翔科技Maven快照仓库</name>
<url>https://nexus.feixiang.com/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<build>
<plugins>
<!-- 源码插件:打包时生成-sources.jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 文档插件:打包时生成-javadoc.jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
各角色的部署操作
小崔(后端开发)的日常快照部署:
# 小崔完成一个功能后,部署快照版供黄俪联调
mvn clean deploy
# 效果:1.2.0-SNAPSHOT上传到feixiang-snapshots仓库
# 黄俪的pom.xml里写<version>1.2.0-SNAPSHOT</version>,Maven自动下载最新快照
白歌(架构师)的正式发布:
# 1. 先修改pom.xml版本号:1.2.0-SNAPSHOT -> 1.2.0
mvn versions:set -DnewVersion=1.2.0
# 2. 部署到发布仓库(此时version不含SNAPSHOT,走repository路径)
mvn clean deploy
# 效果:1.2.0上传到feixiang-releases仓库,不可覆盖
李眉(运维)的私服检查:
# 李眉在Nexus管理界面确认构件已到位
# 访问 https://nexus.feixiang.com/
# 在maven-snapshots仓库看到:com/feixiang/order-service/1.2.0-SNAPSHOT/
# 在maven-releases仓库看到:com/feixiang/order-service/1.2.0/
易错点与常见问题
误区一:只配repository,不配snapshotRepository
错误认知:"我们公司只有一个仓库,Release和Snapshot都往里面放,所以只写repository就够了。"
纠正:Maven 3.x的deploy插件会严格区分version类型。如果你的version是1.0-SNAPSHOT但pom.xml里只有<repository>没有<snapshotRepository>,deploy会失败:
Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy
Deployment failed: repository element was not specified in the POM
inside distributionManagement element
错误信息具有误导性——它说"repository element was not specified",实际上你的repository是配了的,只是Maven要求SNAPSHOT必须走snapshotRepository。正确做法是两者都配,即使指向同一个URL:
<distributionManagement>
<repository>
<id>feixiang</id>
<url>https://nexus.feixiang.com/repository/maven-public/</url>
</repository>
<snapshotRepository>
<id>feixiang</id>
<url>https://nexus.feixiang.com/repository/maven-public/</url>
</snapshotRepository>
</distributionManagement>
误区二:id随便写,与settings.xml不对应
错误认知:"id就是个名字,我写nexus或my-repo都行,反正URL对了就能传上去。"
纠正:id是认证绑定的唯一标识。deploy插件上传时,会用distributionManagement里的id去settings.xml里找同名的<server>标签。如果id不匹配,即使URL正确、账号密码在settings.xml里存在,Maven也会匿名上传,被私服拒绝:
Return code is: 401, ReasonPhrase: Unauthorized
反例:
<!-- pom.xml -->
<repository>
<id>feixiang-releases</id>
<url>https://nexus.feixiang.com/...</url>
</repository>
<!-- settings.xml -->
<server>
<id>feixiang-release</id> <!-- 注意:releases vs release,少了个s -->
<username>deployer</username>
<password>xxx</password>
</server>
id差一个字符,认证就会失败。建议建立团队规范:id命名统一、大小写敏感、定期核对。
误区三:http协议未配置镜像时直接使用
错误认知:"我们公司内网Nexus用http,不需要证书,直接写URL就行。"
纠正:Maven 3.8.1+默认阻止http协议的仓库(中央仓库强制https)。如果你的私服还在用http,需要在settings.xml中配置镜像例外,或者在命令行添加参数:
# Maven 3.8.1+ 临时允许http(不推荐用于生产)
mvn clean deploy -Dmaven.wagon.http.ssl.insecure=true
正确做法:将私服升级为https,或在settings.xml中配置允许http的镜像:
<mirror>
<id>feixiang-http-allow</id>
<mirrorOf>feixiang-releases,feixiang-snapshots</mirrorOf>
<url>http://nexus.feixiang.com/...</url>
<blocked>false</blocked>
</mirror>
小结
distributionManagement是Maven部署体系的"导航地图",它通过repository和snapshotRepository两个标签,精确控制Release和Snapshot构件的上传目的地。配置时需注意三点:
- 两者缺一不可,SNAPSHOT版本必须有snapshotRepository
- id必须与settings.xml中的server对应,否则认证失败
- 协议选择要符合Maven版本要求,3.8.1+默认禁用http
配合maven-source-plugin和maven-javadoc-plugin,可以确保源码和文档随主构件一起部署,提升团队协作效率。
本章与全局的关系:本章解决了"往哪部署"的配置问题。下一章将讲解mvn deploy命令本身——deploy生命周期阶段、与install的区别、以及SNAPSHOT的特殊部署行为。