Maven和Git
阅读提示
这页建议按“Maven 基础 -> 常用命令 -> 依赖机制 -> Git 实战”顺序复习。
面试时优先说你在项目里的真实使用场景,不要只背概念。
Maven&Git(了解)
适用范围:以下构建与依赖说明以 Maven 3.9.x 为基准,Git 示例适用于 Git 2.x;JAR 说明参照 Java SE 21,WAR 说明参照 Jakarta Servlet 6.0。插件目标需要对应插件及兼容的 JDK,不属于 Maven 核心自带的通用命令。
1、Maven 是什么?
Maven 主要服务于基于 Java 平台的项目构建、依赖管理和项目信息管理。
Maven 的主要功能分为 4 点:
- 依赖管理系统
- 多模块构建
- 一致的项目结构
- 一致的构建模型和插件机制
2、Maven 常用命令
mvn archetype:generate:通过 Archetype 插件生成项目,替代旧的archetype:create。mvn compile:编译主源代码。mvn test-compile:编译测试源代码。mvn test:通常由 Surefire 插件运行单元测试;集成测试需另外配置相应插件。mvn package:按项目的 packaging 类型打包,例如 JAR 或 WAR。mvn verify:执行到验证阶段,包含之前的打包阶段,并运行绑定到这些阶段的检查。mvn install:将项目构件及 POM 安装到本地仓库,供其他本地项目引用。mvn deploy:将构件发布到配置的远程 Maven 仓库,供其他项目使用;不是把应用部署到 Web 服务器。mvn site:生成项目站点,需要相应站点插件配置。mvn clean:清理构建输出,通常是target/,不会清空本地依赖仓库。mvn clean package:先清理,再执行到打包阶段。mvn clean package -DskipTests:通常仍编译测试代码,但跳过 Surefire 测试执行。mvn clean package -Dmaven.test.skip=true:跳过测试编译和执行;Compiler、Surefire、Failsafe 插件支持此属性,其他插件需查看各自配置。
Maven 的阶段与插件的目标不同:执行阶段会依次执行同一生命周期内之前的阶段,再由绑定的插件完成工作。例如,普通 JAR 项目的默认生命周期可简化为:
compile → test-compile → test → package → verify → install → deploy
↑
mvn package 执行到这里为止
clean 属于独立的 clean 生命周期;以上省略了资源处理等阶段。jetty:run 等是插件目标,能否运行取决于插件配置与版本;旧的 tomcat:run 不能视为适用于任意 Tomcat 版本的启动方式。历史上的 eclipse:eclipse 生成 Eclipse 项目配置,eclipse:clean 删除这些配置,两者都不是 Java 编译命令。Maven Eclipse Plugin 已退役,现代 Eclipse 项目宜通过 m2e 导入 POM。
官方资料:构建生命周期、Archetype generate、跳过测试、已退役的 Eclipse 插件。
3、Maven能解决什么问题?为什么要用?
在没有使用Maven的情况下,开发应用时需手动确定引入哪些第三方JAR包,然后去查找这些JAR包并将它们手动导入到项目中。同时,处理各个JAR包之间的兼容性和冲突问题是一项繁琐的任务。
完成JAR包的配置后,想要将应用打包成WAR包同样需要进行复杂的操作。整个应用的编译、测试和部署流程都显得特别繁杂。
引入 Maven 后,可以统一这些工作流程,但选中某个依赖版本不代表它一定与业务代码兼容,仍需检查和测试。Maven 主要服务于 Java 项目的管理和构建,其主要功能包括:
- 提供了一套依赖管理机制,简化了JAR包的引入和解决冲突的过程。
- 提供了标准化的构建流程,包括编译、测试、打包、发布等步骤。
- 定义了一套标准化的项目结构,使得项目组织更加清晰有序。
4、依赖的解析机制是什么呢?
依赖解析既要决定“使用哪个版本”,也要决定“从哪里取得构件”,不能只理解为下载 JAR。
- Maven 读取 POM 并收集传递依赖,根据 scope、optional 和 exclusions 等规则形成依赖图。同一依赖出现多个版本时,通常按“路径最近”选择;路径深度相同则先声明者优先,不是自动选最新版本。
- 当前项目的
dependencyManagement可以管理依赖版本,包括传递依赖的版本;但仅在那里声明依赖不会自动把它加入项目,实际使用仍需相应依赖路径。 - 确定坐标后,优先使用符合当前解析上下文的本地仓库构件;缺失时按生效的远程仓库、镜像和仓库策略获取并缓存。本地有文件也不等于一定可用,仓库来源信息及更新策略仍会影响解析。
system范围是例外:通过systemPath指向本地文件,不从仓库获取,且降低可移植性,应尽量改用普通仓库依赖。RELEASE、LATEST是旧式动态版本写法,Maven 3 已弃用,不宜用于新项目。应显式固定发布版本,避免构建结果随仓库变化。1.0-SNAPSHOT表示可更新的开发版本。远程仓库通过版本目录下的maven-metadata.xml将它映射到时间戳构件,客户端是否检查更新受仓库updatePolicy等配置影响,并非每次都重新下载。逻辑版本仍是1.0-SNAPSHOT,不应把内部缓存处理概括成“删除时间戳后使用”。
例如,未用 dependencyManagement 覆盖版本时:
app → A → C:1.0 (到 C 深度为 2)
app → B → D → C:2.0 (到 C 深度为 3)
结果:选 C:1.0,而非版本号更大的 C:2.0。这只是版本仲裁,不能保证 A、B 都兼容选中的 C。可以用 mvn dependency:tree 查看实际依赖路径,再决定统一版本或排除某条传递依赖。
官方资料:依赖机制、本地仓库、远程仓库与快照、POM 版本要求。
5、jar包和war包有什么区别?
JAR包(Java Archive)和WAR包(Web Application Archive)都是Java中用于打包和部署应用程序的归档文件,但它们有不同的用途和特点:
- JAR包(Java Archive):
用途: 主要用于打包Java类、资源文件和库,通常用于独立的Java应用程序或Java库的发布。
结构: JAR 包可以包含 Java 类、资源和配置文件。普通 JAR 不会自动把依赖打进去;即使嵌套了其他 JAR,标准类加载器也不会自动加载它们,需要框架加载器等额外机制。
执行方式: JAR 不一定可执行。通过
java -jar启动时,需在META-INF/MANIFEST.MF中指定Main-Class,并提供具有正确入口方法的类及所需运行时依赖。部署: 可执行 JAR 可以通过
java -jar启动,普通库 JAR 通常作为其他项目的依赖使用。WAR包(Web Application Archive):
用途: 用于打包和部署Web应用程序,包含Web应用所需的所有资源,例如Servlet、JSP、HTML、CSS、JavaScript等。
结构: WAR包包含Web应用的目录结构,通常包括
WEB-INF目录、WEB-INF/lib目录(用于存放依赖的JAR文件)和WEB-INF/classes目录(用于存放编译后的Java类)。执行方式: WAR包通常被部署在支持Servlet规范的Web容器(如Tomcat、Jetty)中,并由容器负责执行。
部署: WAR 可通过容器提供的部署机制发布;复制到应用目录只是其中一种方式,是否自动部署、是否解压取决于容器配置。
总结:
- JAR包主要用于打包和部署独立的Java应用程序或库。
- WAR包主要用于打包和部署Web应用程序,包括Web应用所需的所有资源。
- JAR 可以是库或可执行应用;标准 WAR 通常交给兼容 Servlet 版本的容器运行。部分框架也支持包含嵌入式容器的可执行 WAR,这属于额外打包机制。
官方资料:Java SE 21 JAR 规范、Jakarta Servlet 6.0 规范。
6、如何解决Git冲突?
1、git冲突的场景
- 情景一:执行
merge、rebase或cherry-pick,Git 无法自动整合变更时。 - 情景二:多人更新同一远端分支,本地提交未包含远端新提交时,普通
push通常被拒绝为非快进;在本地取回并整合提交时,才可能发生内容冲突。
push 是传输对象并请求更新远端引用,不会在远端替你执行 merge。pull 则先 fetch,再按显式选项或配置执行 merge/rebase 等整合操作;pull --ff-only 遇到分叉会直接失败。
Git 通常根据共同祖先和两边的修改进行三方合并。同一个文本文件中互不重叠的修改往往可以自动合并;同一片段的不同修改、修改与删除、重命名冲突等可能需要人工处理。不同文件的变更也可能存在业务上的不兼容,即使 Git 没有报告冲突,也需要检查结果。
2、冲突解决方法
合并冲突时,用编辑器或 IDE 结合双方意图修改内容,清除 <<<<<<<、=======、>>>>>>> 等冲突标记,然后暂存解决结果。删除冲突文件时使用 git rm。继续命令取决于正在进行的操作:merge 可用 git merge --continue(或提交),rebase 应用 git rebase --continue,cherry-pick 应用 git cherry-pick --continue,不能全部套用 add → commit。
下面是本地合并冲突的示例,假定 feature 是已有本地分支、开始前工作区干净;命令仅供说明:
git merge feature
# 如果报告冲突:编辑 src/Example.java,保留正确内容并删除冲突标记
git add src/Example.java
git diff --cached # 审查暂存的解决结果
git status # 确认没有尚未解决的冲突
git merge --continue不打算继续当前操作时,可按操作类型使用 git merge --abort 或 git rebase --abort。开始整合前应提交或妥善保存未提交工作,避免中止时难以恢复原状。
若起因是推送被拒绝,应先取回远端更新,再根据团队约定在本地 merge 或 rebase,解决冲突并检查结果后再正常推送。不要将强制推送当作解决内容冲突的方法。
官方资料:git-push、git-pull、git-merge、git-rebase。
