maven命令详解

1 是啥

Apache开源项目,Java项目的构建和管理工具。跨平台的项目管理工具,帮助实现项目的构建、测试、打包和部署。

Maven 提供标准的软件生命周期模型和构建模型,通过配置就能对项目进行全面管理。跨平台保证在不同os使用相同命令来完成相应任务。Maven 将构建的过程抽象成一个个生命周期过程,在不同阶段使用不同已实现插件来完成相应工作,极大避免设计和脚本编码的重复,实现复用。

2 能干啥

  1. 用maven方便的创建项目,基于archetype(原型”或“典型)可创建多种类型的java项目
  2. Maven仓库对jar包(artifact)进行统一管理,避免jar文件的重复拷贝和版本冲突
  3. 团队开发,管理项目的RELEASE和SNAPSHOT版本,方便多模块(Module)项目的各模块间快速集成

本文介绍基于 Apache Maven 3 的项目构建的基本概念和方法。Maven 是一套标准的项目构建和管理工具,使用统一规范的脚本进行项目构建,简单易用,摒弃 Ant 中繁琐的构建元素,并具有较高可重用性。读完本文,你将了解 Maven 的基本概念和使用它进行项目构建的基本方法。

Maven vs Ant

Ant 也是 Apache 组织下的一个跨平台的项目构建工具,它是一个基于任务和依赖的构建系统,是过程式的。开发者需要显示的指定每一个任务,每个任务包含一组由 XML 编码的指令,必须在指令中明确告诉 Ant 源码在哪里,结果字节码存储在哪里,如何将这些字节码打包成 JAR 文件。Ant 没有生命周期,你必须定义任务和任务之间的依赖,还需要手工定义任务的执行序列和逻辑关系。这就无形中造成了大量的代码重复。

Maven 不仅是一个项目构建工具还是一个项目管理工具。它有约定的目录结构(表 1)和生命周期,项目构建的各阶段各任务都由插件实现,开发者只需遵照约定的目录结构创建项目,再配置文件中生命项目的基本元素,Maven 就会按照顺序完成整个构建过程。Maven 的这些特性在一定程度上大大减少了代码的重复。

3 常用命令

3.1 maven install

可将项目本身编译并打包到本地仓库,其他项目引用本项目的jar包时不用去私服下载jar包,直接从本地就能拿到刚编译打包好的项目jar包,避免了每次都需要重新往私服发布jar包的痛苦。

修改服务端,如manage层、dao层的项目时,若IDEA没有自动编译,则调试时易出奇怪错误,明明代码已改好,但debug时还在报错,就是项目没有编译完成造成,看到的改好的代码没变成class文件,因此,服务端的文件改动后,若发现没效果,可能是没编译,这时就能使用maven install编译。

IDEA可很方便创建project、module,但修改各module的版本时,会遇到import报错,这就是maven仓库没有对应包,仍需使用到install,注意是lifecycle里的install:

就能将已有的module打包到maven仓库,再修改版本号,不会影响项目里其他module。

3.2 mvn clean

清理环境,清除target文件夹。

3.3 mvn compile

编译,将Java源文件编译成class文件。

3.4 mvn test

执行test目录下的测试用例。

3.5 mvn package(打包)

将Java工程打成jar包。

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< com.javaedge.bigdata:sparksql-train >------------------
[INFO] Building sparksql-train 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sparksql-train ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sparksql-train ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/javaedge/Downloads/sparksql-train/target/classes
[INFO] 
[INFO] --- scala-maven-plugin:3.1.3:compile (default) @ sparksql-train ---
[WARNING]  Expected all dependencies to require Scala version: 2.11.8
[WARNING]  com.javaedge.bigdata:sparksql-train:1.0 requires scala version: 2.11.8
[WARNING]  com.twitter:chill_2.11:0.9.3 requires scala version: 2.11.12
[WARNING] Multiple versions of scala libraries detected!
[INFO] /Users/javaedge/Downloads/sparksql-train/src/main/scala:-1: info: compiling
[INFO] Compiling 31 source files to /Users/javaedge/Downloads/sparksql-train/target/classes at 1679561149150

[WARNING]     peopleRowRDD
[WARNING]     ^
[WARNING] warning: there was one deprecation warning; re-run with -deprecation for details
[WARNING] two warnings found
[INFO] prepare-compile in 0 s
[INFO] compile in 20 s
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sparksql-train ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/javaedge/Downloads/sparksql-train/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sparksql-train ---
[INFO] No sources to compile
[INFO] 
[INFO] --- scala-maven-plugin:3.1.3:testCompile (default) @ sparksql-train ---
[WARNING]  Expected all dependencies to require Scala version: 2.11.8
[WARNING]  com.javaedge.bigdata:sparksql-train:1.0 requires scala version: 2.11.8
[WARNING]  com.twitter:chill_2.11:0.9.3 requires scala version: 2.11.12
[WARNING] Multiple versions of scala libraries detected!
[WARNING] No source files found.
[INFO] 
[INFO] --- maven-surefire-plugin:2.13:test (default-test) @ sparksql-train ---
[INFO] Tests are skipped.
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ sparksql-train ---
[INFO] Building jar: /Users/javaedge/Downloads/sparksql-train/target/sparksql-train-1.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  27.695 s
[INFO] Finished at: 2023-03-23T16:46:10+08:00
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

3.6 mvn clean package -Dmaven.test.skip=true

跳过单元测试。

4 避坑指南

多模块的项目,注意父 pom 会设置 JDK 版本,注意对齐版本号:

5 Maven 插件和仓库

Maven 本质是插件框架,核心并不执行任何具体的构建任务,仅定义抽象的生命周期,所有这些任务都交给插件。每个插件都能完成至少一个任务,每个任务即是一个功能,将这些功能应用在构建过程的不同生命周期,保证了:

  • 拿来即用
  • 避免 maven 本身的繁杂和冗余

将生命周期的阶段与插件目标绑定,特定阶段完成具体构建任务。如下代码在 validate 阶段执行 maven-antrun-plugin 的 run 目标,具体任务在 <target></target> 元素中定义。

<plugins> 
    <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-antrun-plugin</artifactId> 
        <version>1.6</version> 
<executions> 
<execution> 
    <id>version</id> 
   <phase>validate</phase> 
   <configuration> 
<target> 
   具体任务
</target> 
</configuration> 
<goals> 
<goal>  run  </goal> 
    </goals> 
</execution> 
    </executions> 
    </plugin> 
</plugins>

Maven 项目中的插件,依赖和项目构建的输出都可由 Maven 坐标唯一区分,基于这种机制,Maven 将所有项目的构建文件放置一个统一位置 - Maven 仓库。所有 Maven 项目可从同一 Maven 仓库中获取自己所需要的依赖 JAR,这节省了磁盘资源。实际 Maven 项目不需要存储依赖的文件,只需在 POM 文件生成依赖关系,在构建时 Maven 就会自动去仓库中下载。

在安装了 Maven 的机器上,会生成一个 ~\.m2\repository 目录,即本地仓库,当 Maven 查找需要的依赖时:

  • 先会在本地查找,若本地仓库中存在,则直接使用
  • 否则 Maven 去远程仓库查找,查找到后下载到本地进行使用。远程中央仓库地址 http://repo1.maven.org/

当个人所在的网络无法访问公共的 Maven 仓库时,可在 settings.xml 设置代理服务器。打开 ~\.m2\settings.xml,若没有则复制 $Maven_HOME/conf/settings.xml 到此路径下,加入:

<proxies> 
  <proxy> 
     <active>true</active> 
     <protocol>http</protocol> 
     <host> 代理地址 </host> 
     <port>8080</port> 
     <username> 用户名 </username> 
     <password> 密码 </password> 
   </proxy> 
</proxies>

6 依赖、聚合和继承

6.1 依赖

项目中依赖的 Jar 包可通过依赖的方式引入,通过在 dependencies 元素下添加 dependency 子元素,可声明一或多个依赖。通过控制依赖的范围,可指定该依赖在什么阶段有效。

Maven 的几种依赖范围:

6.2 传递依赖

依赖具有传递性,如 Project A 依赖 Project B,B 依赖 C,则 B 对 C 的依赖关系也会传递给 A。

若我们的项目引用了一个jar包,而该jar包又引用了其他jar包。则默认情况下,项目编译时,Maven会把直接引用、间接引用的jar包都下载到本地( ~/.m2/repository )。

若不需要这种传递性依赖,可用 <optional> 去除这种依赖传递:

<dependency> 
  <groupId>commons-logging</groupId> 
  <artifactId>commons-logging</artifactId> 
  <version>1.1.1</version> 
  <optional>true<optional> 
</dependency>

假设第三方的 jar 包中没有使用 <optional> 去除某些依赖的传递性,则可在当前 POM 文件中使用 <exclusions> 元素声明排除依赖,exclusions 可以包含一个或者多个 exclusion 子元素,因此可以排除一个或者多个传递性依赖。如

<dependency>    
     <groupId>org.springframework</groupId>  
     <artifactId>spring-core</artifactId>  
     <exclusions>  
           <exclusion>      
                <groupId>commons-logging</groupId>          
                <artifactId>commons-logging</artifactId>  
           </exclusion>  
     </exclusions>  
</dependency>

6.3 依赖冲突

若项目中多个jar同时引用相同的jar时,会产生依赖冲突,但Maven采用两种避免冲突的策略,因此在Maven中不存在依赖冲突:

6.3.1 短路优先

本项目 =》 A.jar =》B.jar =》 X.jar 本项目=》 C.jar =》 Xjar

6.3.2 声明优先

引用路径长度相同时,pom.xmI中谁先被声明,就使用谁。

7 多模块项目 / 聚合

现实中一个项目往往由多个 project 构成,构建时,当然不想针对多个 project 分别执行多次构建命令,易产生遗漏也大大降低效率。Maven 的聚合功能可通过一个父模块将所有要构建的模块整合。

7.1 父模块pom文件的配置

packaging 类型须是pom:

<groupId>com.java.ad</ groupId>
<artifactId>java-ad</artifactId>
<packaging>pom</ packaging>
<version>1.O-SNAPSHOT</version>

7.2 聚合子模块

使用modules标签:

<modules>
  <module>ad-eureka</module>
  <module>java-ad-service</module>
  <module>ad-gateway</module>
</modules>

将父模块的打包类型声明为 POM,通过 <modules> 将各模块集中到父 POM。如下其中 <module></module> 中间的内容为子模块工程名的相对路径。

聚合

<modules>    
  <module>../com.javaedge.project1</module> 
  <module>../com.javaedge.project2</module> 
</modules>

父类型的模块,不需要有源代码和资源文件,即没有 src/main/java 和 src/test/java 目录。Maven 会:

  • 先解析聚合模块的 POM 文件
  • 分析要构建的模块,并通过各模块的依赖关系计算模块的执行顺序,根据这潜在关系依次构建模块
  • 将各子模块聚合到父模块后,就能对父模块进行一次构建命令,完成全部模块的构建

8 继承

继承是可重用性即消除重复编码的行为。Maven 中继承的用意和OOP一致。与聚合的实现类似,通过构建父模块将子模块共用的依赖,插件等进行统一声明,在聚合和继承同时使用时,可用同一父模块来完成这两个功能。

如将 com.javaedge.parent 模块声明为 project1、project2 的父模块,那么我们在 project1、2 中用如下代码声明父子关系,如:

<parent> 
 <groupId>com.javaedge.mavenproject</groupId> 
 <artifactId>com.javaedge.parent</artifactId> 
 <version>0.0.1-SNAPSHOT</version> 
 <relativePath>../com.javaedge.parent/pom.xml</relativePath> 
</parent>

父模块只是用来声明一些可共用的配置和插件信息,所以它也像聚合模块一样,只需包括一个 POM 文件,其它项目文件如 src/main/java 都不需要。

聚合和继承存在一些共性和潜在联系,实际应用中,经常将聚合模块的父模块和继承的父模块定义为同一个。并非所有 POM 元素都能被继承,如下是可继承的元素列表。

8.1 可继承元素列表

名称 描述
groupId 项目组 ID
version 项目版本
description 描述信息
organization 组织信息
inceptionYear 创始年份
url 项目的 url 地址
developers 开发者
contributors 贡献者信息
distributionManagerment 部署信息
issueManagement 缺陷跟踪系统
ciManagement 持续继承信息
scm 版本控制信息
mailingList 邮件列表信息
properties 自定义的属性
dependencies 依赖配置
dependencyManagement 依赖管理配置
repositories 仓库配置
build 源码目录,插件管理等配置
reporting 报告配置

9 排除依赖

如只想下载直接引用的jar包,在 pom.xml 做如下配置(给出需要排除的坐标):

10 Maven 属性

在 POM 文件中常需要引用已定义的属性以降低代码冗余,提高代码可重用性:

  • 不仅能降低代码升级的工作量
  • 也能提高代码正确率

有些属性是用户自定义的,有些属性是可直接引用的已定义变量。

10.1 Maven 的可用属性类型

内置属性

这种属性跟 Maven Project 自身有关,比如要引入当前 Project 的版本信 息,那么只需要在使用的位置引用 ${version} 就行。

Setting 属性

上文中已经提到 Maven 自身有一个 settings.xml 配置文件,它里面含有包括仓库,代理服务器等一些配置信息,利用 ${settings.somename} 就可以得到文件里相应元素的值。

POM 属性

这种属性对应 POM 文件中对应元素的值,如 project.groupId<groupId></groupId>{project.groupId} 对应 `<groupId></groupId>` 中的值,{project.artifactId} 对应了 <artifactId> </artifactId > 中的值。

系统环境变量

可用 env.namename{name} 获得相应 name 对应的环境变量的值,如 {env.JAVA_HOME} 得到的就是 JAVA_HOME 的环境变量值。

用户自定义变量

使用最频繁和广泛的变量,完全由用户定义。POM 文件加入 元素并将自定义属性作为其子元素。格式如:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <java.version>1.8</java.version>
    <skipTests>true</skipTests>
    <springfox-swagger.version>2.9.2</springfox-swagger.version>
</properties>

11 Maven 3 特性

Maven 3 在性能和灵活性方面都比 Maven2 有很大提升,新特性总结:

  1. 兼容低版本 Maven,即向后兼容,因此用户可以将 Maven2 的项目移植到 Maven3

  2. 性能优化。CPU 利用率更高,内存消耗更小,经过优化的 Maven3 比 Maven2 构建速度快出 50% 以上,这对于构建大型项目的开发者来说无疑会节省大量时间

  3. 在早先的版本中,开发者必须在子模块中指定父版本,当进行代码的迁移或升级时,这会带来额外的维护工作,Maven3.1 将会消除在子模块上指定父版本需要

  4. Maven3 改善了错误报告,它会在错误报告中提供指向 Maven Wiki 页面的链接,这样开发者可以方便的查看更全面的错误描述和可能的原因。

  5. 增加 Maven Shell,通常可在系统自带 console 里执行 Maven 命令,但通过自安装 Maven Shell 提高生成速度,它是一个是 Maven 的命令行接口工具,可以缓存解析过的 POM,避免了重复调用 Maven 的启动成本。Maven Shell 不属于 Maven 发行包的一部分,需要单独下载

  6. IDEA 实现 Maven 和 IDEA 的集成,与一个使用更广泛的 IDE 进行集成从而为开发者带来的便利是不言而喻的

12 总结

Maven 有着许多实用的特点,它使用了标准的目录结构和部署。这就使得开发人员能够适应不同的项目,并且不用学习任何结构方面新的东西,也不用掌握特殊的指令来构建结构。

#晒一晒我的offer##23届找工作求助阵地##软件开发薪资爆料##我的实习求职记录#
全部评论

相关推荐

牛客963010790号:为什么还要收藏
点赞 评论 收藏
分享
点赞 3 评论
分享
牛客网
牛客企业服务