写点什么

Maven 实战(一)——坐标规划

  • 2010 年 12 月 12 日
  • 本文字数:3009 字

    阅读完需:约 10 分钟

坐标是什么?为什么要规划?

坐标是Maven 最基本的概念,它就像每个构件的身份证号码,有了它我们就可以在数以千万计的构件中定位任何一个我们感兴趣的构件。举个最简单的例子,如果没有坐标,使用JUnit 的时候,用户就需要去下载依赖jar 包,用依赖的方式,简单配置使用如junit:junit:4.8.2 就可以了。这里第一个junit 是groupId,第二个junit 是artifactId,4.8.2 是version。

Maven 的很多其他核心机制都依赖于坐标,其中最显著的就是仓库和依赖管理。对于仓库来说,有了坐标就知道在什么位置存储构件的内容,例如 junit:junit:4.8.2 就对应仓库中的路径/junit/junit/4.8.2/junit-4.8.2.pom/junit/junit/4.8.2/junit-4.8.2.jar这样的文件,读者可以直接访问中央仓库地址看到这样的仓库布局,或者浏览本地仓库目录~/.m2/repository/以获得直观的体验。

依赖的配置也是完全基于坐标的,例如:

复制代码
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>

有了正确的坐标,Maven 才能够在正确的位置找到依赖文件并使用,这里值为 test 的 scope 是用来控制该依赖只在测试时可用,与坐标无关。

正因为坐标是 Maven 核心的核心,因此规划正确的坐标至关重要,如果你使用了模糊不清的坐标,那么你的用户就很难找到你的构件,或者即使找到了,也容易写错。错误的使用坐标,还会造成冲突,如果你也使用 junit 这样的 groupId,那会发生什么?下面先看一些不是很规范的坐标使用方式。

坐标规划的原则

滥用坐标、错用坐标的样例比比皆是,在中央仓库中我们能看到SpringFramework 有两种坐标,其一是直接使用springframework 作为groupId,如springframework:spring-beans:1.2.6,另一种是用org.springframework 作为groupId,如org.springframework:spring-beans:2.5。细心看看,前一种方式显得比较随意,后一种方式则是基于域名衍生出来的,显然后者更合理,因为用户能一眼根据域名联想到其Maven 坐标,方便寻找。因此新版本的SpringFramework 构件都使用org.springframework 作为groupId。由这个例子我们可以看到坐标规划一个原则是_ 基于项目域名衍生_。其实很多流行的开源项目都破坏了这个原则,例如JUnit,这是因为Maven 社区在最开始接受构件并部署到中央仓库的时候,没有很很严格的限制,而对于这些流行的项目来说,一时间更改坐标会影响大量用户,因此也算是个历史遗留问题了。

还有一个常见的问题是将groupId 直接匹配到公司或者组织名称,因为乍一看这是显而易见的。例如组织是zoo.com,有个项目是dog,那有些人就直接使用groupId com.zoo 了。如果项目只有一个模块,这是没有什么问题的,但现实世界的项目往往会有很多模块,Maven 的一大长处就是通过多模块的方式管理项目。那dog 项目可能会有很多模块,我们用坐标的哪个部分来定义模块呢?groupId 显然不对,version 也不可能是,那只有artifactId。因此要这里有了另外一个原则,用artifactId 来定义模块,而不是定义项目。接下来,很显然的,项目就必须用groupId 来定义。因此对于dog 项目来说,应该使用groupId com.zoo.dog,不仅体现出这是zoo.com 下的一个项目,而且可以与该组织下的其他项目如com.zoo.cat 区分开来。

除此之外,artifactId 的定义也有最佳实践,我们常常可以看到一个项目有很多的模块,例如api,dao,service,web 等等。Maven 项目在默认情况下生成的构件,其名称不会是基于artifactId,version 和packaging 生成的,例如 api-1.0.jardao-1.0.jar等等,他们不会带有 groupId 的信息,这会造成一个问题,例如当我们把所有这些构件放到 Web 容器下的时候,你会发现项目 dog 有 api-1.0.jar,项目 cat 也有 api-1.0.jar,这就造成了冲突。更坏的情况是,dog 项目有 api-1.0.jar,cat 项目有 api-2.0.jar,其实两者没什么关系,可当放在一起的时候,却很容易让人混淆。为了让坐标更加清晰,又出现了一个原则,即在 _ 定义 artiafctId 时也加入项目的信息 _,例如 dog 项目的 api 模块,那就使用 artifactId dog-api,其他就是 dog-dao,dao-service 等等。虽然连字号是不允许出现在 Java 的包名中的,但 Maven 没这个限制。现在 dog-api-1.0.jar,cat-2.0.jar 被放在一起时,就不容易混淆了。

关于坐标,我们还没谈到 version,这里不再详述因为读者可以从 Maven: The Complete Guide 中找到详细的解释,简言之就是使用这样一个格式:

复制代码
< 主版本 >.< 次版本 >.< 增量版本 >-< 限定符 >

其中主版本主要表示大型架构变更,次版本主要表示特性的增加,增量版本主要服务于 bug 修复,而限定符如 alpha、beta 等等是用来表示里程碑。当然不是每个项目的版本都要用到这些 4 个部分,根据需要选择性的使用即可。在此基础上 Maven 还引入了 SNAPSHOT 的概念,用来表示活动的开发状态,由于不涉及坐标规划,这里不进行详述。不过有点要提醒的是,由于 SNAPSHOT 的存在,自己显式地在 version 中使用时间戳字符串其实没有必要。

Classifier

Classifier 可能是最容易被忽略的 Maven 特性,但它确实非常重要,我们也需要它来帮助规划坐标。设想这样一个情况,有一个 jar 项目,就说是dog-cli-1.0.jar吧,运行它用户就能在命令行上画一只小狗出来。现在用户的要求是希望你能提供一个 zip 包,里面不仅包含这个可运行的 jar,还得包含源代码和文档,换句话说,这是比较正式的分发包。这个文件名应该是怎样的呢?dog-cli-1.0.zip?不够清楚,仅仅从扩展名很难分辨什么是 Maven 默认生成的构件,什么是额外配置生成分发包。如果能是dog-cli-1.0-dist.zip就最好了。这里的 dist 就是 classifier,默认 Maven 只生成一个构件,我们称之为主构件,那 _ 当我们希望 Maven 生成其他附属构件的时候,就能用上 classifier_。常见的 classifier 还有如dog-cli-1.0-sources.jar表示源码包,dog-cli-1.0-javadoc.jar表示 JavaDoc 包等等。制作 classifier 的方式多种多样,其中最重要的一种是使用 Maven Assembly Plugin ,感兴趣的读者可以进一步研究。

小结

本文是InfoQ Maven 专栏的第一篇,讨论的是Maven 坐标的规划,包括如何正确的使用groupId、artifactId、version,以及classfier。笔者在维护Maven 中央仓库的工作过程中遇到过各种各样模糊的甚至是错误的坐标,它们的存在给广大Maven 用户带来的极大的不便。本文抛出一些较好的实践,帮助大家更好的使用Maven。如果读者有相关的经验总结,也请不吝分享。

关于作者

许晓斌(Juven Xu),国内社区公认的Maven 技术专家、Maven 中文用户组创始人、Maven 技术的先驱和积极推动者。对Maven 有深刻的认识,实战经验丰富,不仅撰写了大量关于Maven 的技术文章,而且还翻译了开源书籍《Maven 权威指南》,对Maven 技术在国内的普及和发展做出了很大的贡献。就职于Maven 之父的公司,负责维护Maven 中央仓库,是Maven 仓库管理器Nexus(著名开源软件)的核心开发者之一,曾多次受邀到淘宝等大型企业开展Maven 方面的培训。此外,他还是开源技术的积极倡导者和推动者,擅长Java 开发和敏捷开发实践。他的个人网站是: http://www.juvenxu.com

【编者按】InfoQ 中文站有幸邀请到 Sonotype(Maven 背后的公司)在中国唯一的员工、《Maven 实战》的作者许晓斌先生,在 InfoQ 中文站开辟 Maven 的专栏,为开发者带来一些 Maven 的高级话题,以及他积累多年的 Maven 经验分享。

2010 年 12 月 12 日 21:4020305

评论 1 条评论

发布
用户头像
什么时候可以出个maven之类的专栏呢
2021 年 04 月 16 日 09:49
回复
没有更多了
发现更多内容

架构实战营-模块二作业

^_^

架构实战营

模块二作业

TIEDPAG

极客时间【架构实战营】第二期 模块二作业

Geek_91606e

架构实战营

香!阿里技术官甩我一份283页Java核心笔记,竟含9大核心

Java~~~

Java 架构 面试 JVM 多线程

模块7作业

gevin

架构实战营

算法2021版第0期毕业总结

bin

Java + opencv 实现老照片特效滤镜

张音乐

OpenCV 图像处理 9月日更 特效 老照片

从基础到实战!阿里P9用28天,总结出这份亿级活动高并发系统设计手册

Java 架构 面试 后端 高并发

背完这套Java面试八股文,自动解锁面试牛逼症被动技能

北游学Java

Java 数据库 面试 算法 开发框架

Django 配置夯实,再补充几个配置项,够够的了

梦想橡皮擦

9月日更

惊讶!阿里大佬总结的图解Java小册火了,完整版笔记开放下载

Java~~~

Java 架构 面试 微服务 JVM

🌏【架构师指南】带你彻底认识Paxos算法、Zab协议和Raft协议的原理和本质

浩宇天尚

ZAB raft协议 paxos协议 9月日更

架构作业 - 模块一

Leo Zhao

架构实战营

谈 C++17 里的 Builder 模式

hedzr

c++ 设计模式

微信朋友圈高性能架构

Geek_db27b5

阿里进阶专用:Mycat权威指南,不怕从零开始,只怕从未启程

Java~~~

Java MySQL 数据库 架构 面试

阿里技术专家,紧跟潮流,解读spring微服务架构技术的演进

Java~~~

Java 架构 面试 微服务 Spring Cloud

Prometheus relabel 透析与实战

卓丁

Prometheus relabel_config

Fil价格强势上涨!fil的行情走势如何?Fil未来五年多少钱一枚?

区块链 分布式存储 fil币未来价格预估消息 fil大涨 fil价格行情

【LeetCode】二叉树的深度Java题解

HQ数字卡

算法 LeetCode 9月日更

设计微博系统中”微博评论“的高性能高可用计算架构

架构0期-Bingo

双非本科跨专业5面京东,8600小时后收到通知,流下喜悦泪水

Java~~~

Java 架构 面试 微服务 JVM

【架构实战营作业】模块二——朋友圈高性能架构

聆息

字节面试官狂问我:如何设计一个高并发系统?

Java架构师迁哥

Python开发篇——添加mysqlclient

DisonTangor

Python MySQL

奉若神明!阿里技术专家开源ApacheDubbo核心源码笔记

Java~~~

Java spring 架构 面试 dubbo

阿里技术专家亲码:满干货“Redis核心笔记”,全篇无尿点

Java~~~

Java redis 架构 面试 中间件

图解 | Linux内存回收之LRU算法

程序员 架构 面试

架构师实战营 附一作业(按接口隔离原则优化设计无人机引导直升机攻击的类图)

代廉洁

架构实战营

激动!阿里技术官纯手打,1263页并发编程全系笔记,限时开源

Java~~~

Java 架构 面试 多线程 并发

0基础架构入门 - 2(架构设计复杂度模型和应对之道)

felix

架构实战营 0基础架构入门

Maven实战(一)——坐标规划_Java_许晓斌_InfoQ精选文章