一、Maven是什么?
Maven翻译过来是"专家"、"内行"的意思。其实就是一个项目管理工具,专门帮Java开发者搞定三件事:项目构建、依赖管理、项目信息管理。
你可以把它想象成一个管家:
依赖管理:管家帮你去超市(中央仓库)采购项目需要的各种jar包,你不用自己跑腿。
项目构建:管家按照标准流程帮你编译代码、运行测试、打包部署,你只需要下命令就行。
项目信息管理:管家帮你记录项目的基本信息------叫什么名字、谁开发的、版本号多少。
Maven最牛的地方在于,它把项目开发和管理的过程抽象成了一个项目对象模型(POM)。就是用一个pom.xml文件来描述你的项目------你是谁、你需要什么、你要产出什么。Maven只要读懂这个文件,就知道该怎么整你的项目了。
二、为什么需要Maven?
在Maven出现之前,Java项目的构建非常困难,用IDE(Eclipse/IDEA)直接构建:每个人IDE配置不同,在你机器上跑得好好的代码,换台电脑就是各种报错。编译、测试、部署都是手工操作,步骤繁琐还容易出错。用Ant构建:Ant比纯手工强一点,但它的配置文件和Maven比差远了。Ant没有约定的目录结构,你必须明确告诉它"源代码在哪、编译后的文件放哪",每一个步骤都要自己写。更致命的是,Ant没有生命周期概念,也没有集成依赖管理------也就是说,jar包你还是得自己去找、自己下载、自己放到项目里。
所以Maven应运而生。它带来了三个核心改进:
-
约定优于配置:你只要按照Maven规定的目录结构放代码,它自动就能识别,不用额外配置。
-
标准化生命周期:编译、测试、打包、部署这些步骤被抽象成标准阶段,一条命令就能完成整个流程。
-
统一的依赖管理:再也不用手动下载jar包了,在pom.xml里声明一下,Maven自动帮你搞定。
三、Maven的两大核心能力
Maven最核心的能力就两个:依赖管理和项目构建。
3.1 依赖管理
什么是依赖?简单说,你的项目要用到别人的代码(比如JUnit、Spring、MyBatis),这些第三方库就是你的"依赖"。
依赖管理解决的核心问题有三个:
第一,自动下载。你在pom.xml里写上依赖的坐标(后面会讲),Maven自动从仓库下载对应的jar包。
第二,统一版本管理。不同jar包之间可能存在版本依赖关系------A依赖B的2.0版本,B又依赖C的3.0版本。手工管理这些版本关系简直噩梦,Maven帮你自动处理。
第三,避免版本冲突。当多个依赖引用了同一个jar包的不同版本时,Maven有一套机制来决定用哪个版本,避免冲突。
3.2 项目构建
项目构建就是"从源代码到可运行软件"的整个过程:编写代码 → 编译 → 测试 → 打包 → 部署。
Maven把构建过程标准化了,每个阶段对应一个命令:
mvn compile:编译源代码
mvn test:运行测试
mvn package:打包(生成jar或war)
mvn install:安装到本地仓库
mvn deploy:部署到远程仓库
这些命令需要我们背会。
四、Maven的核心概念逐个拆解
4.1 坐标(Coordinates)
Maven的世界里有成千上万个jar包,怎么唯一识别一个?靠坐标。Maven的坐标由三部分组成:
groupId:组织标识,一般是公司域名的反写 + 项目名。比如com.alibaba、org.springframework。这相当于"姓氏",告诉你这个jar包是谁家的。
artifactId:项目名或模块名。比如fastjson、spring-core。这相当于"名字",告诉你这个jar包具体是什么。
version:版本号。比如1.2.83、5.3.23。版本号通常遵循"大版本.分支版本.小版本"的格式,SNAPSHOT表示快照版(开发中),RELEASE表示正式版。
坐标就像是每个jar包的家庭住址------groupId是小区名,artifactId是楼栋号,version是门牌号。Maven根据这个地址去仓库里精准定位你要的那个jar包。
4.2 仓库(Repository)
Maven从哪儿下载jar包?从仓库。仓库有三种类型:
本地仓库(Local Repository):在你电脑上的一个文件夹,你自己放哪里了就在哪里。Maven第一次下载某个jar包后,会把它存在本地仓库,下次再用就直接从本地拿,不用重复下载。
中央仓库(Central Repository):Maven官方维护的公共仓库,包含了绝大多数流行的开源Java构件。不需要任何配置,Maven默认就从这里下载。
远程仓库/私服(Remote Repository):中央仓库和公司内部搭建的私有仓库。比如:阿里云,腾讯云,华为云。
Maven查找一般是本地没有就去私服找,私服没有就去中央仓库下载并缓存到私服和本地。
4.3 生命周期(Lifecycle)
Maven有三套相互独立的生命周期:
clean生命周期:清理项目。只有三个阶段------pre-clean、clean(删除target目录)、post-clean。
default生命周期:构建项目。这是最核心的生命周期,包含了从编译到部署的所有阶段:
validate → compile → test → package → verify → install → deploy
site生命周期:生成项目站点文档。pre-site → site → post-site → site-deploy。
生命周期是"抽象的",它只定义了"做什么"的顺序,具体"怎么做"由插件来完成。比如compile阶段由maven-compiler-plugin执行编译,test阶段由maven-surefire-plugin执行测试。
当你执行mvn test时,Maven会从default生命周期的第一个阶段开始,顺序执行到test阶段为止。所以mvn test会自动先执行compile。mvn clean package则是先跑完clean生命周期的clean阶段,再跑default生命周期直到package。
4.4 依赖范围(Scope)
Maven项目在运行过程中有三套classpath:编译时的、测试时的、运行时的。依赖范围就是控制某个jar包出现在哪套classpath中。常见的scope有四种:
compile(默认):编译classpath有效,测试classpath有效,运行classpath有效。典型场景:Spring、Commons等核心依赖。
test:编译classpath无效,测试classpath有效,运行classpath无效。典型场景:JUnit单元测试。
provided:编译classpath有效,测试classpath有效,运行classpath无效。典型场景:Servlet API(运行环境已提供)。
runtime:编译classpath无效,测试classpath有效,运行classpath有效。典型场景:JDBC驱动(编译时只需接口)。
scope就像给依赖贴标签------compile是"全程陪同",test是"只陪测试",provided是"只管前半程",runtime是"后半程才出现"。搞清楚这个,你就明白为什么Servlet API要用provided------因为Tomcat服务器本身就带了这个jar包,打包时再打进去反而会冲突。
4.5 依赖传递与依赖阻断
依赖传递:A依赖B,B依赖C,那么A会自动获得C的依赖(除非被阻断)。这极大地减少了重复声明。
依赖阻断有两种方式:
可选依赖(Optional):B在依赖C时加上<optional>true</optional>,表示"这个依赖是可选的,A要不要用自己决定"。
排除依赖(Exclusion):A在依赖B时主动排除掉C,用<exclusions>标签实现。
依赖传递就像家族继承------你爸有的东西你自动就有。但如果你爸有些东西你不想继承(或者跟你自己的东西冲突了),你可以选择"放弃继承"或者"主动剔除"。
五、Maven教会我的思维方式
好的工具不是让你做更多的事,而是让你做更少的事。没有Maven的时候,我们花大量时间在"找jar包、配环境、解决冲突"这些重复劳动上。有了Maven,这些事被自动化了,我们可以把精力放在真正有价值的事情上------写业务代码。
Maven的核心思想"约定优于配置",与其让每个人自由发挥导致混乱,不如定一套标准,大家都按标准来。这样我们有了统一的规则,提高效率。
当我们写的代码越来越多,就会发现,Maven带给我们的方便真的非常大,你会由衷感谢它。