3. Maven 进阶
3.1 pom.xml 文件
- 核心地位 :类比 Make 的 MakeFile、Ant 的 build.xml,是 Maven 项目的核心配置文件,基于项目对象模型(POM) 定义项目基本信息,描述构建流程、声明依赖关系等。
- 核心作用:统一管理项目配置,包括坐标、依赖、构建插件、生命周期绑定等,确保项目构建的标准化和可复用性。
3.2 坐标
3.2.1 坐标概念
- Maven 中构件的唯一标识,通过一组元素定位依赖或项目自身,确保在仓库中能精准找到目标构件。
3.2.2 坐标元素及要求
| 元素 | 必要性 | 含义 | 示例 |
|---|---|---|---|
| groupId | 必须 | 组织标识,通常为 "公司网址反写 + 项目名",体现项目所属组织 / 团队 | cn.tx.maven(tx 为公司 / 团队标识,maven 为项目名) |
| artifactId | 必须 | 项目 / 模块名称,区分同一 groupId 下的不同模块 | Hello(独立模块)、HelloFriend(依赖 Hello 的模块) |
| version | 必须 | 版本号,格式为 "大版本。分支版本。小版本 - 限定词" | 0.0.1-SNAPSHOT(SNAPSHOT 表示快照版)、1.0-RELEASE(RELEASE 表示稳定版) |
| packaging | 可选 | 打包方式,默认值为 "jar",其他常见值有 "war"(Web 项目)、"pom"(父项目) | jar、war、pom |
| classifier | 可选 | 描述构件附属信息,用于区分同一坐标下的不同附属构件(如源码包、文档包) | sources(源码包)、javadoc(文档包) |
3.2.3 坐标意义
- 解决 "构件唯一标识" 问题,让机器可自动根据坐标查找、下载依赖,无需人工管理 JAR 包路径。
3.3 依赖
3.3.1 依赖意义
- 解决项目对外部库(如 JUnit)或内部模块的依赖管理问题,自动处理递归依赖(如 A 依赖 B,B 依赖 C,则 A 自动获取 C),避免手动下载、复制 JAR 包的繁琐和版本冲突。
3.3.2 依赖配置格式
在 pom.xml 的 <dependencies> 标签内声明依赖,示例如下:
xml
<dependencies>
<!-- 第三方依赖(JUnit) -->
<dependency>
<groupId>junit</groupId> <!-- 组织标识 -->
<artifactId>junit</artifactId> <!-- 依赖名称 -->
<version>4.9</version> <!-- 版本号 -->
<scope>test</scope> <!-- 依赖范围(仅测试时生效) -->
</dependency>
<!-- 内部模块依赖(Hello 模块) -->
<dependency>
<groupId>cn.tx.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope> <!-- 默认范围,编译/测试/运行均生效 -->
</dependency>
</dependencies>
3.3.3 第三方依赖查找方法
- 访问 Maven 中央仓库官网:https://mvnrepository.com/
- 在搜索框输入依赖名称(如 mybatis、fastjson)
- 选择目标依赖及对应版本,复制生成的坐标配置到 pom.xml 中
3.4 依赖范围(Scope)
3.4.1 核心作用
控制依赖在不同 classpath(主代码、测试代码、运行时) 中的生效范围,避免不必要的依赖打包或版本冲突。
3.4.2 常见依赖范围及特性
| 依赖范围 | 主代码 classpath 有效 | 测试代码 classpath 有效 | 运行时 classpath 有效 | 打包时包含 | 示例 |
|---|---|---|---|---|---|
| compile | Y | Y | Y | Y | log4j(项目运行全程依赖) |
| test | N | Y | N | N | JUnit(仅测试代码用) |
| provided | Y | Y | N | N | servlet-api(运行时由 Tomcat 提供) |
| runtime | N | Y | Y | Y | JDBC 驱动(编译时用接口,运行时用实现) |
| system | Y | Y | N | N | 本地非仓库的 JAR 包(需指定 systemPath,不推荐) |
| import | - | - | - | - | 仅在 dependencyManagement 中使用,导入其他 POM 的依赖配置 |
3.5 依赖传递与依赖控制
3.5.1 依赖传递
- 概念:当项目 A 依赖项目 B,项目 B 依赖项目 C 时,A 会自动继承 B 对 C 的依赖(A→B 为第一直接依赖,B→C 为第二直接依赖,A→C 为传递依赖)。
- 示例:HelloFriend 依赖 Hello,MakeFriend 依赖 HelloFriend,则 MakeFriend 会自动依赖 Hello。
3.5.2 依赖范围对传递依赖的影响
传递依赖的生效范围由 "第一直接依赖范围" 和 "第二直接依赖范围" 共同决定,核心规则如下:
| 第一直接依赖范围 \ 第二直接依赖范围 | compile | test | provided | runtime |
|---|---|---|---|---|
| compile | compile(生效) | 不生效 | 不生效 | runtime(生效) |
| test | test(生效) | 不生效 | 不生效 | test(生效) |
| provided | provided(生效) | 不生效 | provided(生效) | provided(生效) |
| runtime | runtime(生效) | 不生效 | 不生效 | runtime(生效) |
3.5.3 依赖阻断(可选依赖)
- 作用:阻止依赖传递,避免不需要的间接依赖被引入。
- 配置方式 :在依赖中添加
<optional>true</optional>,示例:
xml
<dependency>
<groupId>cn.tx.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<optional>true</optional> <!-- HelloFriend 依赖 Hello,但 MakeFriend 不继承 Hello -->
</dependency>
3.5.4 依赖排除(Exclusion)
- 作用:强制排除依赖中的某个间接依赖(如解决版本冲突)。
- 配置方式 :在依赖中添加
<exclusions>标签,示例:
xml
<dependency>
<groupId>cn.tx.maven</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion> <!-- 排除 HelloFriend 传递的 Hello 依赖 -->
<groupId>cn.tx.maven</groupId>
<artifactId>Hello</artifactId>
</exclusion>
</exclusions>
</dependency>
3.6 仓库
3.6.1 仓库概念与分类
- 概念 :存储 Maven 构件(JAR、WAR、POM 等)的位置,分为三类:
- 本地仓库 :用户本地存储构件的目录,默认路径为
~/.m2/repository(Windows:C:\Users\用户名\.m2\repository),首次执行 Maven 命令时自动创建。 - 中央仓库 :Maven 社区维护的公共仓库(http://repo1.maven.org/maven2),包含绝大多数开源 Java 构件,无需配置即可访问(需联网)。
- 远程仓库:企业 / 团队搭建的私有仓库(如私服)或第三方公共仓库,用于存储内部构件或代理中央仓库。
- 本地仓库 :用户本地存储构件的目录,默认路径为
3.6.2 依赖搜索顺序
- 优先查找本地仓库,若存在则直接使用;
- 本地仓库不存在时,查找远程仓库(如私服),若存在则下载到本地仓库后使用;
- 远程仓库不存在时,查找中央仓库,下载到本地仓库后使用;
- 所有仓库均不存在时,构建失败并报错。
3.6.3 本地仓库配置
- 全局配置 (影响所有用户):修改
%MAVEN_HOME%\conf\settings.xml,指定<localRepository>路径:
xml
<localRepository>D:\maven-repository</localRepository>
- 用户配置 (仅影响当前用户):在
~/.m2目录下创建settings.xml,配置同上(优先级高于全局配置)。
3.7 生命周期
3.7.1 生命周期概念
- Maven 对项目构建流程(清理、编译、测试、打包、部署)的标准化抽象,本身不执行具体操作,仅定义 "阶段(Phase)" 及执行顺序,具体操作由 "插件" 完成。
- 三套独立生命周期:Clean(清理)、Default(构建)、Site(生成站点),彼此独立,可单独执行。
3.7.2 核心生命周期及阶段
| 生命周期 | 核心阶段(按执行顺序) | 阶段作用 | 绑定的核心插件 |
|---|---|---|---|
| Clean | pre-clean → clean → post-clean | 清理项目输出(如 target 目录) | maven-clean-plugin:clean(clean 阶段) |
| Default | validate → compile → test → package → install → deploy | 编译源码→测试→打包→安装到本地仓库→部署到远程仓库 | maven-compiler-plugin:compile(compile 阶段)、maven-surefire-plugin:test(test 阶段)、maven-jar-plugin:jar(package 阶段,JAR 打包) |
| Site | pre-site → site → post-site → site-deploy | 生成项目文档(如 API 文档)→部署文档到远程站点 | maven-site-plugin:site(site 阶段)、maven-site-plugin:deploy(site-deploy 阶段) |
3.7.3 生命周期执行规则
- 执行某个阶段时,Maven 会自动执行该阶段之前的所有阶段 (如执行
mvn install,会依次执行 validate→compile→test→package→install); - 可同时执行多个阶段,按输入顺序执行(如
mvn clean package,先执行 Clean 生命周期的所有阶段,再执行 Default 生命周期到 package 阶段)。
3.9 Maven 继承与聚合
3.9.1 继承
- 核心作用:消除多模块项目的配置重复,统一管理公共依赖、插件、仓库等,提升项目安全性和可维护性(如多个模块共用 JUnit、Spring 版本)。
3.9.2 可继承的 POM 元素
| 类别 | 可继承元素 | 说明 |
|---|---|---|
| 项目标识 | groupId、version | 子项目默认继承父项目的 groupId 和 version,无需重复配置 |
| 项目信息 | description、organization、developers | 项目描述、组织信息、开发者信息等公共元数据 |
| 依赖管理 | dependencies、dependencyManagement | dependencies:子项目自动继承依赖;dependencyManagement:子项目需显式声明依赖,但无需指定版本(继承父项目版本) |
| 构建配置 | build(源码目录、插件配置)、reporting | 统一的源码路径、插件版本(如 maven-compiler-plugin) |
| 仓库配置 | repositories、pluginRepositories | 子项目继承父项目的仓库地址,无需重复配置 |
3.9.3 IDEA 实现继承(以父项目 parent 为例)
-
创建父项目 :
- 打包方式设为
pom(父项目仅用于管理,不生成构件):
xml
<packaging>pom</packaging>- 在父项目 pom.xml 中通过
<modules>声明子模块:
xml
<modules> <module>core</module> <!-- 子模块 1 --> <module>manage</module> <!-- 子模块 2 --> <module>portal</module> <!-- 子模块 3 --> </modules> - 打包方式设为
-
创建子项目 :
- 选择 "New Module",父项目指定为上述 parent,子项目自动继承 groupId 和 version;
- 子项目 pom.xml 中通过
<parent>标签关联父项目:
xml
<parent> <groupId>cn.tx.extends</groupId> <artifactId>parent</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>core</artifactId> <!-- 子项目仅需配置 artifactId -->
3.9.4 聚合
- 核心作用 :多模块项目中,通过 "聚合项目(父项目)" 一键执行所有子模块的构建操作(如
mvn install父项目,会自动构建所有子模块),无需逐个模块执行命令。 - 实现方式 :父项目通过
<modules>标签聚合子模块,与继承共用父项目配置,实现 "一键构建 + 配置统一"。
3.9.5 properties 属性
- 作用:定义全局变量,统一管理版本号、路径等,避免重复书写(如统一 Spring、MySQL 版本)。
- 配置示例:
xml
<properties>
<spring.version>5.3.20</spring.version> <!-- 定义 Spring 版本变量 -->
<mysql.version>5.1.47</mysql.version> <!-- 定义 MySQL 版本变量 -->
</properties>
<!-- 引用变量 -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version> <!-- 引用 Spring 版本变量 -->
</dependency>
</dependencies>
4. Maven 私服架构
4.1 私服介绍
4.1.1 私服概念与价值
- 概念:企业在局域网内搭建的 Maven 远程仓库,兼具 "私有构件存储" 和 "中央仓库代理" 功能。
- 核心价值 :
- 存储企业内部构件(如自研的工具类 JAR、业务模块),供内部项目复用;
- 代理中央仓库,避免所有项目直接联网下载,节省带宽并提高依赖获取速度;
- 控制依赖权限,确保内部构件不对外泄露,同时统一管理第三方依赖版本。
4.1.2 Nexus 介绍
- Nexus 是主流的 Maven 仓库管理器,支持:
- 创建多种类型仓库(宿主、代理、仓库组);
- 可视化管理构件(上传、删除、搜索);
- 权限控制(不同用户角色管理不同仓库)。
4.2 Nexus 实战
4.2.1 Nexus 安装与启动(以 Nexus 2.12.0 为例)
-
安装准备 :
- 解压
nexus-2.12.0-01-bundle.zip到无中文路径的目录(如D:\nexus); - 配置端口(可选):修改
conf/nexus.properties中的application-port(默认 8081,示例改为 8079):
properties
application-port=8079 application-host=0.0.0.0 - 解压
-
服务操作 (管理员身份运行 CMD):
- 安装服务:
cd D:\nexus\nexus-2.12.0-01\bin→ 执行nexus.bat install; - 启动服务:
nexus.bat start; - 停止服务:
nexus.bat stop; - 卸载服务:
nexus.bat uninstall。
- 安装服务:
-
访问界面 :打开浏览器输入
http://localhost:8079/nexus,默认用户名admin,密码admin123。
4.2.2 Nexus 仓库类型
| 仓库类型 | 作用 | 示例 |
|---|---|---|
| Hosted(宿主仓库) | 存储企业内部构件,分为:- Releases:稳定版本构件(如 1.0-RELEASE)- Snapshots:测试版本构件(如 0.0.1-SNAPSHOT)- 3rd party:第三方非中央仓库构件(如自研的特殊 JAR) | 公司内部的 tx-utils-1.0-RELEASE.jar 存储到 Releases 仓库 |
| Proxy(代理仓库) | 代理远程公共仓库(如中央仓库),自动下载构件到本地,供内部项目使用 | 代理 Maven 中央仓库,项目请求 JUnit 时,Nexus 先从中央仓库下载到 Proxy 仓库,再提供给项目 |
| Group(仓库组) | 合并多个 Hosted/Proxy 仓库,提供统一访问地址,简化项目配置 | 创建 public 仓库组,包含 Releases、Snapshots、Proxy(中央仓库),项目仅需配置 public 地址即可访问所有仓库 |
| Virtual(虚拟仓库) | 兼容 Maven 1 版本构件,目前极少使用 | - |
4.2.3 将项目发布到私服
-
配置客户端权限 (修改
settings.xml):在<servers>标签内配置私服的账号密码(用于校验上传权限):xml
<server> <id>releases</id> <!-- 与私服 Releases 仓库 ID 对应 --> <username>admin</username> <password>admin123</password> </server> <server> <id>snapshots</id> <!-- 与私服 Snapshots 仓库 ID 对应 --> <username>admin</username> <password>admin123</password> </server> -
配置项目发布地址 (修改项目 pom.xml):通过
<distributionManagement>指定私服的 Releases/Snapshots 仓库地址:xml
<distributionManagement> <!-- 稳定版本发布到 Releases 仓库 --> <repository> <id>releases</id> <!-- 与 settings.xml 中 server 的 id 一致 --> <url>http://localhost:8079/nexus/content/repositories/releases/</url> </repository> <!-- 测试版本发布到 Snapshots 仓库 --> <snapshotRepository> <id>snapshots</id> <!-- 与 settings.xml 中 server 的 id 一致 --> <url>http://localhost:8079/nexus/content/repositories/snapshots/</url> </snapshotRepository> </distributionManagement> -
执行发布命令 :
- 进入项目根目录,执行
mvn clean deploy; - 若项目版本为
RELEASE,自动发布到 Releases 仓库;若为SNAPSHOT,自动发布到 Snapshots 仓库。
- 进入项目根目录,执行
4.2.4 从私服下载 JAR 包
方式 1:配置镜像(推荐,全局生效)
修改 settings.xml,将所有依赖请求转发到私服仓库组:
xml
<mirrors>
<mirror>
<id>nexus-maven</id>
<mirrorOf>*</mirrorOf> <!-- 拦截所有请求,转发到私服 -->
<name>Nexus Maven</name>
<url>http://localhost:8079/nexus/content/groups/public/</url> <!-- 私服仓库组地址 -->
</mirror>
</mirrors>
方式 2:配置 Profile(全局 / 项目生效)
-
全局配置 (修改
settings.xml):xml
<!-- 定义 Profile --> <profiles> <profile> <id>dev</id> <!-- 依赖仓库 --> <repositories> <repository> <id>nexus</id> <url>http://localhost:8079/nexus/content/groups/public/</url> <releases><enabled>true</enabled></releases> <!-- 允许下载稳定版 --> <snapshots><enabled>true</enabled></snapshots> <!-- 允许下载测试版 --> </repository> </repositories> <!-- 插件仓库(Maven 插件从私服下载) --> <pluginRepositories> <pluginRepository> <id>public</id> <url>http://localhost:8079/nexus/content/groups/public/</url> </pluginRepository> </pluginRepositories> </profile> </profiles> <!-- 激活 Profile --> <activeProfiles> <activeProfile>dev</activeProfile> </activeProfiles> -
项目配置 (修改项目 pom.xml):在 pom.xml 中添加上述
<repositories>和<pluginRepositories>配置(仅当前项目生效,不推荐,易重复)。
4.2.5 第三方 JAR 包发布到私服(以 fastjson 为例)
步骤 1:配置私服 3rd party 仓库权限
修改 settings.xml,添加 3rd party 仓库的账号密码:
xml
<server>
<id>thirdparty</id> <!-- 与 3rd party 仓库 ID 对应 -->
<username>admin</username>
<password>admin123</password>
</server>
步骤 2:执行部署命令
在 CMD 中执行以下命令(需指定 JAR 包路径、坐标、私服 3rd party 仓库地址):
bash
mvn deploy:deploy-file
-DgroupId=com.alibaba
-DartifactId=fastjson
-Dversion=1.1.37
-Dpackaging=jar
-Dfile=D:\fastjson-1.1.37.jar <!-- 本地 JAR 包路径 -->
-Durl=http://localhost:8079/nexus/content/repositories/thirdparty/ <!-- 3rd party 仓库地址 -->
-DrepositoryId=thirdparty <!-- 与 settings.xml 中 server 的 id 一致 -->
验证
登录 Nexus 界面,进入 3rd party 仓库,可看到 com/alibaba/fastjson/1.1.37 路径下的 JAR 包。