简易使用 Maven3

打印 上一主题 下一主题

主题 862|帖子 862|积分 2586

Maven3 Core Overview

Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model,POM) ,一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(Phase)中插件(Plugin)目标(Goal)的逻辑。
下图描述了Maven是如何使用POM的,以及POM文件中包含了什么

构建生命周期

生命周期是Maven为了对所有项目的构件过程进行统一和抽象。基于所有的项目构建,都能映射到这样一个生命周期上。Maven生命周期本身是抽象的,那么所有的工作都是交给插件完成的。

不仅如此,Maven总共内建了三套生命周期,这三套都是相互独立的:

  • default,这是默认的生命周期,用于部署项目


  • clean,用于清理项目,比如编译的文件等,一般都存在于target目录中
  • site,用于为当前项目创建web站点
每个生命周期又包含了一些阶段(Phase)default的生命周期由以下几个阶段(Phase)组成:
validate : 校验项目是正确的,并且所有的信息可用
compile :编译
test : 进行单元测试
package : 获取已经编译的源码,并进行打包
verify :检查测试结果
install :将软件包安装到本地,用作本地其他项目的依赖项
deploy :将当前项目发布到远程仓库,提供给其他人用
当default 被使用,就会按照上面的生命周期从上到下构建
更加详细的可以查看官方文档
阶段的执行顺序
生命周期的阶段是按顺序执行的,例如
当想进行单元测试,可以通过使用test 进行,执行如下命令:
  1. mvn test
复制代码
当执行完该执行,会依次执行validate 、compile 、test
如果不确定需要什么,首选的调用是
  1. mvn verify
复制代码
在构建环境中,可以使用下面的指令感觉的构建发布到共享存储库中
  1. mvn clean deploy
复制代码
真正做工作的还是绑定在阶段(Phase)上的插件(Plugin)目标(goal),一个阶段可以绑定零个或多个目标
插件和插件执行目标

基于 约定优先于配置(Convention Over Configuration),Maven为项目提供了定义好的生命周期和一组通用插件。这样的好处就是减少配置,不容易因为配置错误出问题。
Maven是一个以Plugin为核心的框架(或者说将主要的工作委派给了插件)。所有的工作由插件完成,一个插件有一个或多个目标,每个目标代表着插件的不同能力,这样能够最大的提升代码的复用能力。
例如,编译插件有两个目标compile和testCompile,前者源码编译,后者编译测试代码,这对应着default 生命周期的两个阶段,compile 和 test-compile。所以具体来说,就是插件的目标对应着生命周期的阶段

插件有两个类别:
Build plugins构建插件,就是
Reporting Plugins 是生成站点的一部分,通过在POM中的  进行配置
这里可以找到一些常见的插件
目标具有一些参数,这个得查阅具体的文档。例如 compiler:compiler ,这里有它的一些参数
可以通过在pom声明并使用一个插件
  1. <project>
  2. [...]
  3. <build>
  4.   <finalName>simple-webapp</finalName>
  5.   <plugins>
  6.     <plugin>
  7. <dependency>
  8.    
  9. </dependency>
  10. <dependency>
  11.    
  12. </dependency>
  13. <dependency>
  14.    
  15. </dependency>
  16. <dependency>
  17.    
  18. </dependency><groupId></groupId>
  19. <dependency>
  20.    
  21. </dependency>
  22. <dependency>
  23.    
  24. </dependency><artifactId></artifactId>
  25.     </plugin>
  26.   </plugins>
  27. </build>
  28. [...]
  29. </project>
复制代码
Maven中的三类生命周期的每个阶段都绑定了不同的插件的不同目标
如Default生命周期绑定了这些插件。当然,这些也可以自己指定:
  1. <plugins>
  2.   <groupId>...</groupId>
  3.   <artifactId>...</artifactId>
  4.   <version>...</version>
  5.   <executions>
  6.     <execution>
  7.       <id></id>
  8.       <phase>compile</phase>
  9.       <goalos>
  10. <dependency>
  11.    
  12. </dependency>
  13. <dependency>
  14.    
  15. </dependency><goal>pre-compile</goal>
  16.       </goals>
  17.     </execution>
  18.   </executions>
  19. </plugins>
复制代码
之后,可以在命令行来调用这些插件,格式如下
  1. mvn [options] [<goal(s)>] [<phase()s>]
复制代码
有两种写法来调用
  1. # 完整格式
  2. mvn mvn-dependency-plugin:tree
  3. # 简化版
  4. mvn dependency:tree
复制代码
简化版是通过maven插件仓库定义的元数据来建立映射关系的:
  1. <plugin>
  2.   <name>Apache Maven Dependency Plugin</name>
  3.   <prefix>dependency</prefix>
  4.   <artifactId>maven-dependency-plugin</artifactId>
  5. </plugin>
复制代码
当然,指定仓库元数据也可以。 在setting.xml 中指定:
  1. <settings>
  2.   <pluginGroups>
  3.       <pluginGroup>com.your.plugins</pluginGroup>
  4.   </pluginGroups>   
  5. </settings>
复制代码
指定后,Maven就会检查该仓库的元数据。
基本的目录结构

下面是一个项目的目录结构
  1. myprojectdir
  2.   - pom.xml
  3.   - .mvn
  4.     - jvm.config
  5.   - src
  6.     - main
  7.       - java
  8.       - resources
  9.     - test
  10.       - java
  11.       - resources
  12.   - target
复制代码
更加详细的目录布局规范
POM

POM(Project Object Model ,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖。
所有的POM都继承自一个super POM(如果当前POM没有指定parent)
其中定义了基本了目录结构、一个默认的插件仓库和包仓库
以下是最简的POM
  1. <project>
  2.   <modelVersion>4.0.0</modelVersion>
  3.   <groupId></groupId>
  4.   <artifactId></artifactId>
  5.   <version></version>
  6. </project>
复制代码
用坐标(Coordinates)标识一个项目

Maven坐标定义了一组标识,它们以用来标识一个项目,一个依赖,或者Maven POM里的一个插件,下面是一个示例
  1. <project>
  2.   <groupId>org.example</groupId>
  3.   <artifactId>maven-practices</artifactId>
  4.   <version>1.0-SNAPSHOT</version>
  5.   <packaging>jar</packaging>
  6.   <modules>
  7.   <dependencies>
  8.     .....
  9.   </dependencies>
  10.   <build>
  11.     ....
  12.   </build>
  13. </project>
复制代码
标红的为Maven坐标,由三个标签组成:

  • groupId
    创建这个项目的小组/组织/公司名称的逆向域名开头
artifactId
  1. 在groupId下的表示一个单独项目的唯一标识符*
复制代码
version
  1. 项目的特定版本。发布的项目有一个固定的版本,而在开发的项目可以用一个特殊的标识,这种标识给版本后加上一个SNAPSHOT(快照)标识*
复制代码
packaging
  1. 项目的类型,默认是jar,描述了项目打包后的输出。类型为jar产生JAR文件,类型为war产生一个Web应用
复制代码
依赖管理

每个项目工程可以依赖一些开源的构建来提高项目的开发效率,或者是一些开源的插件来执行编译、测试、打包等工作,最后将项目生成的构建安装到本地仓库中。这模块就能供其他Maven项目使用了。
依赖配置
  1. <project>
  2. <dependencies>
  3.   <dependency>
  4.     <groupId></groupId>
  5.     <artifactId></artifactId>
  6.     <version></version>
  7.     <type></type>
  8.     <scope></scope>
  9.     <optional></optional>
  10.     <exclusions>
  11.       <exclusion>
  12. <dependency>
  13.    
  14. </dependency>
  15. <dependency>
  16.    
  17. </dependency><groupId></groupId>
  18. <dependency>
  19.    
  20. </dependency>
  21. <dependency>
  22.    
  23. </dependency><artifactId></artifactId>
  24.       </exclusion>
  25.     </exclusions>
  26.   </dependency>
  27. </dependencies>
复制代码
根元素Project下的dependencies可以包含一个或多个dependency元素,以声明一个或多个项目以来。每个依赖可以包含一下几个元素:

  • groupId、artifactId和version :基本的坐标
  • type:依赖的类型,对应于项目坐标定义的packaging。默认值为jar,改类型还有一下几个值,具体的介绍可以查看官方文档

    • war,通常对应的Web项目
    • ejb-client
    • test-jar

  • scope:依赖的范围。maven在编译(compile )classpath、测试(test)classpath、运行(runtime)classpath三个不同的阶段使用三个不同的classpath ,依赖范围就是用来控制这三种classpath的关系。Maven有以下几种依赖范围:

    • compile:编译依赖范围。默认的依赖范围。使用该依赖范围的Maven依赖,对于以上三种classpath都有效。
    • test:测试依赖范围。只在test 范围有效。例如Junit,它只在需要测试代码时才使用到。
    • provided:已提供依赖范围。在compile和test有效。例如servlet-api,编译和测试的时候许哟使用该依赖,但在运行时无效。典型的例子是servlet-api,由于容器已经提供,就不许哟Maven重复地引入一边
    • runtime:运行时依赖范围。只在runtime和test时有效。例如JDBC驱动实现,项目主代码的编译只需哟JDK提供的JDBC借口,只有在执行测试或者运行项目的时候才需要实现上述借口的具体JDBC驱动。
    • system:系统依赖范围。使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径。该路径与本地系统绑定,移植性低。例如Linux和windows系统中。systemPath元素可以引用环境变量
      1. <systemPath>${java.home}/lib/rt.jar</systemPath>
      复制代码

  • import :导入依赖范围
  • optional:标记依赖是否可选。boolean类型。具体说明
  • exclusions:用来排除传递依赖性
依赖的冲突调解

有以下两个问题。
问题一 ,A有如下依赖关系。
问:这一条路径上有两个不同版本的B,A是选择B (1.0) 还是B(2.0) ?
答:Maven 根据路径最近者优先原则。B (1.0) 的路径长度为3,B(2.0) 为1,Maven会选择B(2.0) 。
问题二 ,A依赖了两个项目。其中Y依赖B(2.0) ,X依赖B (1.0)。
问:A选择哪个版本的B?
答: A会根据X和Y的定义顺序来选择。

可选依赖

假设有如下依赖关系:

牛肉面里面有面条,面条可以通过面粉或荞麦制作,所以面粉和荞麦是可选项。
但在制作面的时候,只需要一种面粉(假如)。那么就需要选择一种面粉
当面(面条)使用两种不同的面粉,需要在POM中声明:
  1. <dependency>
  2.   ...小麦面
  3.   <optional>true</optional>
  4. </dependency>
  5. <dependency>
  6.   ...荞麦面
  7.   <optional>true</optional>
  8. </dependency>
复制代码
当牛肉面需要使用面的时候就需要在Maven中声明
  1. <dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency>
复制代码
在上面的例子中,最好的做法就是为小麦面粉和荞麦面粉分别创建一个maven项目,基于同样的groupId分配不同的artifactId。在各自的POM中声明对应的JDBC驱动依赖,而且不使用可选依赖,只需要根据需要来选择使用。
排除依赖


当项目A使用了项目B,但是项目B依赖的一个构建使用项目C(1.0) 由于C(1.0)的一些问题会导致本身的项目出现错误,但是项目C在新版本中解决了这个问题,那么只需要使用exclusions标签排除项目C(1.0)再依赖项目C(2.0)。如上图所示
项目A的POM:
  1.        ....     B     1.0<dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency><dependency>
  7.    
  8. </dependency>
  9. <dependency>
  10.    
  11. </dependency>      ....<dependency>
  12.    
  13. </dependency>
  14. <dependency>
  15.    
  16. </dependency>  C<dependency>
  17.    
  18. </dependency>
  19. <dependency>
  20.    
  21. </dependency>  >1.0<dependency>
  22.    
  23. </dependency>
  24. <dependency>
  25.    
  26. </dependency><dependency>
  27.    
  28. </dependency>
  29. <dependency>
  30.    
  31. </dependency>       ....     C     2.0  
复制代码
通过使用Maven属性来归类依赖


具体只需要在POM中定义:
  1. <properties>
  2.   <project-A.version>1.0</project-A.version>
  3. </properties>
  4. <dependencies>
  5.   <dependency>
  6.     ....
  7.     <artifactId>子项目A</artifactId>
  8.     <version>${project-A.version}</version>
  9.   </dependency>
  10. </dependencies>
复制代码
依赖优化

可以通过如下命令查看当前项目的已解析依赖(Resolved  Dependency):
  1. mvn dependency:list
复制代码

当这些依赖经过Maven解析后,就会构成一个依赖书,通过这个依赖书就能看到每个依赖是通过哪条路径传入的。可以通过如下命令查看当前项目的依赖树
  1. mvn dependency:tree
复制代码

如果想知道该项目还有哪些问题,可以使用如下命令分析,算是Debug:
  1. mvn dependency:analyze
复制代码
mvn dependency:analyze 只能分析出编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖就发现不了。
下图中提示的是有两个包在该项目中未使用。这一类依赖不应该直接删除而是得仔细考虑。

仓库

任何一个依赖、插件或者项目构建的输出,都可以称为构件。
如果每个项目中都放置着一个重复log4j,这显然不好。这样做不仅仅浪费磁盘空间也难于管理。
文件的复制等操作也会降低构建速度。
Maven则在一个统一位置存储所有的Maven项目共享的构件,这个统一的位置就是仓库
由于坐标的机制,任何一个Maven项目使用任何一个构件的方式都是一样的。为了方便重用,项目构建完毕后生成的构件也可以安装或部署到仓库中,供其他项目使用。

有存储就肯定有存储方式,那肯定是通过文件系统存储了,有文件系统就肯定有文件的路径,用来标识一个文件,Maven有坐标,那么就只需要通过坐标来生成路径。

仓库的分类

maven仓库只分为两类:本地仓库和远程仓库。

当Maven根据坐标去寻找构件的时候,会先查看本地仓库。如果本地仓库没有,那么就去远程仓库下载并存储到本地仓库中。如果都没有则会报错。
本地仓库

每个用户在自己的目录下都有一个路径名为.m2/repository/ 的仓库文件。当然这个位置也可以自己定义。
通过使用Maven的配置文件 (这是用户级别的,只对当前用户可用)
Linux or macOS
  1. ~/.m2/settings.xml
复制代码
Windows
  1. c:\Users\用户名\.m2\settings.xml
复制代码
!  需要注意的是,用户级的配置文件是不存在的,用户需要从Maven安装目录复制 maven安装目录/conf/settings.xml 文件再进行编辑。
也可以创建自己的私有构件,只需要将该项目安装到本地仓库中,做法如下:
  1. mvn clean install
复制代码
中央仓库

中央仓库是Maven自带的远程仓库,它包含大部分开源的构件。
由于最原始的本地仓库是空的,Maven必须要有一个可用的远程仓库,才能在执行Maven命令的时候下载构件。
  1.       central    Maven Central Repository    https://repo.maven.apache.org/maven2    default<dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency>  false      
复制代码
上面这段配置是所有Maven项目都会隐式的(implicitly)继承的Super POM ,该文件包含在Maven-model-builder模块中。
快照版本

Maven中,任何一个项目可能有两种版本,发布版本和快照版本。
考虑这样一个问题。 我和同事一起开发一个项目,我负责Module A,他负责Module B。同事依赖于我的项目。在开发过程中,同事需要使用到最新的版本,用来开发和集成测试。
答案是使用快照;在上述情况下,我只需要将Module A的版本号设定为 1.0-SNAPSHOT,然后发布到内部仓库中,在发布的过程中,Maven会自动为构件打上时间戳。有了时间戳,Maven就能随时找到仓库中该构件的最新版本。
默认情况下,Maven每天检查一次更新(由仓库配置的updatePolicy配置)。也可以使用-U参数手动更新:
  1. mvn clean install-U
复制代码
快照版本很不稳定,所以只应该在内部使用。当需要发布该构件,只需要去掉SNAPSHOT 即可
项目聚合与集成

聚合

聚合就是将多个项目聚合为一个项目。如需聚合两个模块,只需要创建一个新模块,然后通过该模块构建整个项目的所有模块。
该模块需要进行如下声明
  1. <groupId>com.xrtero</groupId>
  2. <artifactId>hello</artifactId>
  3. <version>1.0-SNAPSHOT</version>
  4. <modules>
  5.     <module>maven-test</module>
  6.     <module>maven-test/moduleA</module>
  7.     <module>maven-test/moduleB</module>
  8. </modules>
  9. <packaging>pom</packaging>
复制代码
对于聚合模块来说,打包方式必须声明为POM
module 标记的是被聚合模块的路径。
继承

继承这一特性能够将重复的配置抽取出来,帮助减少不必要的工作。
继承能够建立一个父子关系;子模块需要显示的声明父模块。
relativePath是可选的,因为它默认的路径是上一级,所以这里并不需要声明
  1. <parent>
  2.     <artifactId>hello</artifactId>
  3.     <groupId>com.xrtero</groupId>
  4.     <version>1.0-SNAPSHOT</version>
  5.     <relativePath>../pom.xml</relativePath>
  6. </parent>
复制代码
依赖管理

依赖是可以被继承的。Maven提供的dependencManagement在父模块中定义的元素能够让子模块集成到父模块的依赖配置。又能保证子模块依赖使用的灵活性。
例如,可以用来管理Spring框架子模块的版本:
  1.     11    11    3.1.3.RELEASE<dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency><dependency>
  7.    
  8. </dependency>
  9. <dependency>
  10.    
  11. </dependency><dependency>
  12.    
  13. </dependency>
  14. <dependency>
  15.    
  16. </dependency>org.springframework<dependency>
  17.    
  18. </dependency>
  19. <dependency>
  20.    
  21. </dependency>    spring-core<dependency>
  22.    
  23. </dependency>
  24. <dependency>
  25.    
  26. </dependency>    ${spring.version}<dependency>
  27.    
  28. </dependency>
  29. <dependency>
  30.    
  31. </dependency><dependency>
  32.    
  33. </dependency>
  34. <dependency>
  35.    
  36. </dependency><dependency>
  37.    
  38. </dependency>
  39. <dependency>
  40.    
  41. </dependency>    org.springframework<dependency>
  42.    
  43. </dependency>
  44. <dependency>
  45.    
  46. </dependency>    spring-beans<dependency>
  47.    
  48. </dependency>
  49. <dependency>
  50.    
  51. </dependency>    ${spring.version}<dependency>
  52.    
  53. </dependency>
  54. <dependency>
  55.    
  56. </dependency>   
复制代码
甚至还可以将其他POM的dependencyManagement合并到项目中,需要将scope指定为import。 import 的作用就是将目标POM中的dependencyManagement 配置导入并合并到当前POM的dependencyManagement中。
  1. <dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency><dependency>
  7.    
  8. </dependency>
  9. <dependency>
  10.    
  11. </dependency><dependency>
  12.    
  13. </dependency>
  14. <dependency>
  15.    
  16. </dependency>org.springframework.boot<dependency>
  17.    
  18. </dependency>
  19. <dependency>
  20.    
  21. </dependency>    spring-boot-dependencies<dependency>
  22.    
  23. </dependency>
  24. <dependency>
  25.    
  26. </dependency>    2.7.0<dependency>
  27.    
  28. </dependency>
  29. <dependency>
  30.    
  31. </dependency>    pom<dependency>
  32.    
  33. </dependency>
  34. <dependency>
  35.    
  36. </dependency>    import<dependency>
  37.    
  38. </dependency>
  39. <dependency>
  40.    
  41. </dependency>   
复制代码
插件管理

Maven 提供了 pluginManagement 元素帮助管理插件。在该元素中配置的依赖不会造成实际的插件调用行为。 和 dependencyManagement 作用大体相似。为所有模块重复类似的插件配置使用pluginManagement是最好的办法
常用插件

Maven Archetype

Archetype 是一个模版工具,可以通过一个模版创建一个项目,也可以通过项目创建一个原型(Archetype)
可以通过如下命令创建一个项目,该命令选择的是
maven-archetype-quckstart插件,当然还有其他插件可供选择
  1. mvn archetype:generate -DgroupId=your_group_id -DartifactId=your_artifact_id -DarchetypeArtifactId=maven-archetype-quickstart
复制代码
有待更新
一些其他用法

Root POM中的占位符

通常用在多模块的项目中,如使用shade插件时需要指定一些参数,这些参数每个模块都不一样。

root pom
  1.    这里是占位符  .... 省略了<dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency><dependency>
  7.    
  8. </dependency>
  9. <dependency>
  10.    
  11. </dependency><dependency>
  12.    
  13. </dependency>
  14. <dependency>
  15.    
  16. </dependency><dependency>
  17.    
  18. </dependency>
  19. <dependency>
  20.    
  21. </dependency><dependency>
  22.    
  23. </dependency>
  24. <dependency>
  25.    
  26. </dependency>      ${class-name}<dependency>
  27.    
  28. </dependency>
  29. <dependency>
  30.    
  31. </dependency><dependency>
  32.    
  33. </dependency>
  34. <dependency>
  35.    
  36. </dependency>
复制代码
Module 1 pom 以及其他
  1.        you class name<dependency>
  2.    
  3. </dependency>
  4. <dependency>
  5.    
  6. </dependency><dependency>
  7.    
  8. </dependency>
  9. <dependency>
  10.    
  11. </dependency><dependency>
  12.    
  13. </dependency>
  14. <dependency>
  15.    
  16. </dependency><dependency>
  17.    
  18. </dependency>
  19. <dependency>
  20.    
  21. </dependency>  
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

半亩花草

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表