我们希望你对
Maven
稍有点认识哦~因为我们直接进入Maven
使用实战篇。如果你的项目中使用Maven,却对一大堆的依赖引入一头雾水、束手无策,那么这篇文档可能对你快速梳理依赖管理还原一个干干净净的项目有所帮助~
如果你对
Maven
的还限于clean install
,那么这篇文档也可能对你有所帮助,让我们一起看一看Maven
的其他常用命令,收获一个小技能~如果你需要对
Maven
有进一步的认识,全面了解Maven
的特性或者掌握进阶玩法,那么请跳转文末附录参考,我们引用了一些常用链接。如果看到这里,那么话不多说,让我们行动起来,来看在项目实战中
Maven
的主要使用场景:
- 依赖管理
- 常用cmd
如果你的项目存在依赖管理混乱、依赖版本陈旧难以升级、依赖项超多不易清理,那我们请往下看一看如何还原一个干净清晰的项目依赖管理,让老项目也可以轻松迭代焕发春天~
那在此之前我们需要
Get
:
- 如何管理
Maven
的依赖:知其然,下手干- 如何简化不必要的依赖:简单,就是最好的
Maven的
依赖?Maven
使用pom.xml
来描述项目信息,其中使用dependencyManagement
来定义可以使用的依赖及版本信息,使用dependencies
来为项目引入需要的依赖。项目中我们可能常常见到类似形如:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.lmaxgroupId>
<artifactId>disruptorartifactId>
<version>${disruptor.version}version>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
<version>${mapstruct.version}version>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>${mapstruct.version}version>
<optional>trueoptional>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-log4j2artifactId>
dependency>
<dependency>
<groupId>com.lmaxgroupId>
<artifactId>disruptorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
以上是一个比较典型的“依赖定义+使用”的场景。注意这里使用的一个小技巧。仅使用dependencyManagement
来定义依赖的版本,这样在使用dependencies
引入依赖时就无须关心版本的问题啦!(混乱,往往来于“没事,这样也行,那样也可~”)
懂了!那么我们使用dependencyManagement
定义依赖,使用dependencies
再引入对吧?但是这有什么用呢,我是不是还要经常写一堆依赖(甚至常常从这个项目复制到另一个项目),而且!还要写两遍,我好累,我不写!
别急,让我们再看看如何借助Maven
依赖传递的特点来简化依赖的引用吧!
这里我们要借助
Maven
依赖管理的两个特点:依赖传递和继承。依赖传递:我们引入依赖
A
的时候,如果A
工程又依赖B
、C
,那么Maven
会自动帮我们把B
、C
也引入到项目中。依赖继承:我们可以使用
parent
来引入另一个pom.xml
,这时候Maven
会自动帮我们把引入的这个pom.xml
中定义和使用的依赖引入的项目中。当然,除了使用
parent
直接继承外,我们也可以使用import
方式导入另一个pom.xml
,起到类似的效果。
熟悉springboot
的同学知道,我们使用springboot
来搭建一个后端JavaWeb项目是超快又简洁的,像这样:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.9.RELEASEversion>
<relativePath/>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>spring-boot-demoartifactId>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
这也是个典型的case
,继承spring-boot-starter-parent
的依赖管理,引入spring-boot-starter-web
及其依赖的其他依赖,比如默认内置的小猫咪tomcat
。
在这里,因为spring-boot-starter-parent
已经定义了相关的依赖版本信息,所以我们能够直接引入spring-boot-starter-web
而不用关心版本信息(还有spring-boot-maven-plugin
)。往往依赖的不兼容多是自定义版本的原因哦~
所以,到这里请问你Get
到了吗?简化依赖和敲代码一样,抽象封装,比如将通用的依赖定义在某个pom.xml
或者工程中,使用时仅需要引入一个pom.xml
或者依赖工程,那么项目中60%
的依赖是不是就可以去掉了呢?
当然了,附上一个实战中建议的小技巧,直接使用spring-boot-starter-parent
,springboot
其实帮我们整理了绝大部分常用的依赖,并解决了彼此间可能产生的依赖冲突问题,而在使用上则类似使用spring-boot-starter-web
一样,引入某个starter
基本足够了。
预祝你的项目和你的代码一样,优雅简洁、落落大方。
也许你可能已经有所了解或者常常见到
Maven
的一些命令,比如clean
、compile
、test
、package
、install
、deploy
…这些基本上也覆盖了日常开发的使用范畴,而且借助IDE
操作也通常比较简捷点。
这部分我们大概说下每个命令做了些什么事情,知其然有助于踩坑的时候大概知道为什么,熟悉这些命令对日常的开发效率也会有一点点帮助。
此外,我们不会过多介绍比如Maven
的构建生命周期、插件机制等,有兴趣的同学可以再多了解一点~不过我们会尝试补充一点可能有用的一些命令或者使用小技巧。
其实这里我们可能希望你对Maven的中央仓库、远程仓库、本地仓库有一点点了解,下面在命令的说明中会用到。当然不熟悉也问题不大。我们可以简单有这么个概念:
- 仓库:维护管理依赖
jar
的存储结构,对Maven
会按groupId+artifactId+version
以文件目录的方式进行存储。- 为了加快读取
jar
,Maven
按【本地仓库】>【远程仓库】>【中央仓库】的查找顺序逐次寻找依赖,如果本地仓库不存在依赖,会从远程仓库/中央仓库下载到本地。
clean
:清理编译源码产生的target
目录,其中通常包含编译后的字节码文件,构建产生的jar
也默认产生在此目录。
compile
:编译源码生成字节码文件,默认生成到target
目录,如果使用mapstruct
类似工具,也会在编译期生成源文件,再编译生成字节码文件。
test
:执行src/test/java
目录下的单元测试案例。
package
:将compile
编译产生的字节码文件打包成jar
到target
目录。比如springboot
项目通常使用spring-boot-maven-plugin
打包出一个可执行jar
。
install
:将package
产生的jar
安装到本地仓库。比如我们如果是多模块应用,那么install
到本地仓库后,运行服务时就不会提示模块依赖不存在了,因为Maven
可以从本地仓库找到它。
deploy
:将package
产生的jar
发布到远程仓库。通常如果我们发布一个二方应用sdk
,发布到远程仓库后,其他同学就能从远程仓库上找到它,并使用到他的项目工程中。deploy
通常在项目中用distributionManagement
配置发布的远程仓库信息,并在settings.xml
中设置远程仓库的写账户。
以上是Maven的常用命令,在执行这些命令时,Maven是借助各种插件完成的。这个不是我们关注的重点,有兴趣的同学可以稍多了解一下。
从我个人的使用经验来看,项目中使用Maven掌握以上的使用技巧基本足够啦。如果使用IDEA
的同学,自带的Maven
插件不仅简化了以上命令的使用,也提供了一些可视化的选项,比如可能常用的跳过单元测试。
这部分随缘哈,有用到再补充。
mvn versions:set -DnewVersion=1.0.1-SNAPSHOT
如果是多模块应用,手动挨个修改版本号是不是超麻烦?在项目根pom.xml
目录下,使用以下命令就能轻松设置工程等的版本,在版本迭代时特别好用。比如正式发布升级RELEASE
,开发升级SNAPSHOT
。
mvn versions:set -DnewVersion=1.0.1-SNAPSHOT
01 Maven – Introduction (apache.org)
02 Maven 教程|菜鸟教程