乐途乐途
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
    • HTTP协议
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • MyBatis
    • Spring
    • Spring MVC
    • Maven 入门
    • Maven 进阶
    • Java 设计模式
  • 缓存

    • Redis
联系
阿里云
  • 学习路径
  • 第1章 介绍与核心概念

    • Maven是什么
    • 约定优于配置
  • 第2章 安装与配置

    • 安装与验证
    • settings.xml
    • 本地仓库与镜像
  • 第3章 POM与项目坐标

    • POM
    • GAV坐标
    • packaging
  • 第4章 标准目录布局

    • 标准目录布局
  • 第5章 依赖机制

    • dependencies
    • scope
    • 依赖传递
    • 依赖冲突与调解
    • exclusions
    • optional
    • dependencyManagement
  • 第6章 仓库

    • 仓库体系
    • 本地仓库
    • 远程仓库与镜像
    • 私服
  • 第7章 构建生命周期

    • 生命周期概述
    • clean 生命周期
    • default 生命周期
    • site 生命周期
    • 生命周期与插件绑定
  • 第8章 插件

    • 插件概述
    • maven-compiler-plugin
    • maven-surefire-plugin
    • maven-war-plugin
  • 第9章 继承与聚合

    • parent继承
    • 聚合
    • BOM
    • properties
  • 第10章 属性与资源过滤

    • 资源过滤
    • Profile
  • 第11章 常用命令

    • mvn compile
    • mvn test
    • mvn package
    • mvn clean
    • mvn install
    • mvn dependency:tree
  • 第12章 常见问题与最佳实践

    • 依赖冲突排查
    • 最佳实践

约定优于配置

本章承接"Maven 是什么",深入讲解 Maven 的设计哲学。理解"约定优于配置"(Convention Over Configuration),是理解 Maven 标准目录结构、默认生命周期、隐式插件绑定等所有"默认行为"的钥匙。


核心机制

Maven 提倡约定优于配置,即系统、库和框架应该假定合理的默认值,从而减少对不必要配置的需求。

这句话的潜台词是:如果你按照 Maven 的"约定"做事,你可以写很少的 XML 配置;如果你非要打破约定,你就得写很多配置来解释你的例外。

什么是"约定"?什么是"配置"?

维度约定(Convention)配置(Configuration)
本质行业/工具默认的"潜规则"显式声明的"规则说明"
成本学习一次,终身受益每个项目都要写一遍
示例源代码放在 src/main/java在 pom.xml 里写 <sourceDirectory> 指定别的路径
代价新成员需要学习约定新成员需要读懂你的自定义配置

Maven 中的"约定"体现在哪里?

Maven 的约定渗透在项目的方方面面:

  1. 目录结构约定

    • 源代码必须放在 src/main/java
    • 资源文件必须放在 src/main/resources
    • 测试代码必须放在 src/test/java
    • 构建输出自动放到 target/
  2. 构建生命周期约定

    • compile 阶段默认编译 src/main/java
    • test 阶段默认运行 src/test/java 里的 JUnit 测试
    • package 阶段默认把编译结果打成 JAR
  3. 插件绑定约定

    • compile 阶段自动绑定 maven-compiler-plugin
    • test 阶段自动绑定 maven-surefire-plugin
    • package 阶段自动绑定 maven-jar-plugin
  4. 坐标命名约定

    • groupId 用组织域名的倒写(如 com.feixiang)
    • artifactId 用项目/模块名(如 employee-system)
    • version 用三段式版本号(如 1.0.0)

生活类比:交通规则

想象一座城市的交通系统:

  • "配置"模式的城市:每个路口都没有红绿灯,司机到达路口前必须停车查看一本厚厚的《路口通行规则手册》,确认自己是否有优先权。不同路口规则不同,新手司机天天出事故。
  • "约定"模式的城市:全国统一"红灯停、绿灯行、右转让直行"。你只需学习一次这套约定,到了任何路口都知道该怎么做。偶尔有特殊需求的路口(如单行道、潮汐车道),才会额外立一块标志牌(配置)。

Maven 就是后者:它用一套行业共识的约定,消除了"每个项目都要重新解释规则"的重复劳动。


图示

上图展示了"约定优于配置"的核心价值:约定被所有项目共享,配置只需描述项目的独特之处。在 Ant 时代,每个项目的 build.xml 都是从头写的;在 Maven 时代,三个项目的 pom.xml 可能只有依赖列表不同,其余全部交给约定。


完整示例

场景

飞翔科技有两个项目:

  • 项目 A:employee-system(员工管理系统)
  • 项目 B:payroll-service(薪资计算服务)

CTO 大翔要求所有项目结构统一,方便人员流动时快速上手。

反例:打破约定的代价

假设白歌不喜欢 src/main/java,想把源代码放在 code/src:

<project>
    ...
    <build>
        <sourceDirectory>code/src</sourceDirectory>
        <testSourceDirectory>code/test</testSourceDirectory>
        <outputDirectory>build/classes</outputDirectory>
        <testOutputDirectory>build/test-classes</testOutputDirectory>
        <resources>
            <resource>
                <directory>code/res</directory>
            </resource>
        </resources>
    </build>
</project>

后果:

  • 小崔从 employee-system 调到 payroll-service 时,发现后者源代码在 code/src,前者在 src/main/java,瞬间混乱
  • 李眉写自动化部署脚本时,不得不为每个项目单独判断源代码路径
  • 使用标准 Maven 插件(如 maven-javadoc-plugin)时,插件默认去 src/main/java 找代码,找不到就报错,需要额外配置

正例:遵循约定的收益

两个项目都遵循 Maven 标准结构:

employee-system/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   └── resources/
│   └── test/
│       ├── java/
│       └── resources/

payroll-service/
├── pom.xml
├── src/
│   ├── main/
│   │   ├── java/
│   │   └── resources/
│   └── test/
│       ├── java/
│       └── resources/

两个 pom.xml 都无需声明目录路径,因为 Maven 已经知道去哪里找代码。

收益:

  • 小崔第一天入职,看到目录结构就知道代码在哪、配置在哪、测试在哪
  • 李眉写一个通用的 Jenkins 流水线脚本,适用于所有 Maven 项目
  • 任何标准插件开箱即用,无需额外配置路径

易错点与常见问题

误区一:"约定优于配置"等于"不能配置"

错误认知:"Maven 强制我用 src/main/java,我想改都改不了。"

纠正:Maven 允许你打破约定,只是不推荐。如上例所示,你可以通过 <sourceDirectory> 等标签自定义路径。但每打破一个约定,就要写几行配置,而且团队成员都要学习你的"例外"。约定的价值在于"默认正确",而非"强制服从"。

误区二:IDE 自动生成目录就是"约定"

错误认知:"我用 IDEA 创建 Maven 项目,IDEA 帮我生成了目录,所以这是 IDEA 的约定。"

纠正:IDEA 生成的 src/main/java 不是 IDEA 的发明,而是Maven 的约定。IDEA 只是遵循了 Maven 的规范。如果你用命令行 mvn archetype:generate 创建项目,生成的目录结构和 IDEA 完全一致——这才是约定的力量:工具不同,结构相同。

误区三:约定只关乎目录结构

错误认知:"约定优于配置就是让我把代码放在固定目录里,别的没什么。"

纠正:目录结构只是最显眼的约定。更深层的约定包括:

  • 生命周期阶段的默认顺序(validate → compile → test → package → install)
  • 插件目标的默认绑定(compile 阶段默认用 maven-compiler-plugin:compile)
  • 依赖范围的默认行为(不声明 scope 就是 compile)
  • 版本号的默认解析规则(SNAPSHOT 版本每天检查更新)

这些隐式约定构成了 Maven 的"自动运转"能力,你不需要在 pom.xml 里写"先编译再测试",因为生命周期约定已经帮你排好了。


小结

"约定优于配置"是 Maven 的设计哲学,它通过一套行业共识的默认值(目录结构、生命周期、插件绑定等),让开发者只需描述项目的"独特之处"(如依赖列表、版本号),而无需重复声明"通用规则"。遵循约定,项目配置精简、团队上手快速、工具链兼容性好;打破约定,配置膨胀、协作成本上升、插件兼容性下降。

本章与全局的关系:本章解释了"为什么 Maven 的目录结构和生命周期是固定的"。下一章"安装与配置"将带你亲手搭建 Maven 环境,验证这些约定如何在真实命令中体现。

上一页
Maven是什么