Maven用途、命令、核心概念

Maven 小结

部分转载于:Apache Maven 入门篇 by George Ma

1 Apache Maven 是做什么用的?

  • Maven 是一个项目管理和构建自动化工具。但是对于我们程序员来说,我们最关心的是它的项目构建功能。
  • Maven 使用惯例优于配置的原则 。它要求在没有定制之前,所有的项目都有如下的结构:
目录 目的
${basedir} 存放 pom.xml和所有的子目录
${basedir}/src/main/java 项目的 java源代码
${basedir}/src/main/resources 项目的资源,比如说 property文件
${basedir}/src/test/java 项目的测试类,比如说 JUnit代码
${basedir}/src/test/resources 测试使用的资源
  • 一个 maven 项目在默认情况下会产生 JAR 文件
    • mvn package后建立新目录target/
    • 同时,编译后的 JAR 文件会放在 ${basedir}/target/下
    • 编译后的 classes 会放在${basedir}/target/classes 下面
    • 测试 class 文件放在 target/test-classes/ 目录下面。
  • maven命令:
    • compile:编译,将java源文件编译成class文件
    • test:测试项目,执行test目录下的测试用例
    • package:打包,将项目打成jar包
    • clean:删除target文件夹
    • install:安装将当前项目放到Maven的本地仓库中。供其他项目使用

2 Maven的核心概念

  • POM (Project Object Model)
  • Maven 插件
  • Maven 生命周期
  • Maven 依赖管理
  • Maven 库

POM(Project Object Model)

  • 项目对象模型,pom.xml是整个maven项目的灵魂。

  • 一个项目所有的配置都放置在 POM 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等。比如说,你可以配置 compiler 插件让它使用 java 1.5 来编译。

  • POM 中,groupId, artifactId, packaging, version 叫作 maven 坐标,它能唯一的确定一个项目。有了 maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。一般 maven坐标写成如下的格式:

    groupId:artifactId:packaging:version
    
<!--示例pom.xml-->
<!--project 工程的根标签。-->
<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">

 <!-- 模型版本 -->
<modelversion>4.0.0</modelversion>
    
<!--Maven坐标:com.mycompany.helloworld: helloworld: jar: 1.0-SNAPSHOT-->
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group -->
<groupid>com.mycompany.helloworld</groupid>
<!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
<artifactid>helloworld</artifactid>
<!--打包的类型,有jar、war等等不同类型-->
<packaging>jar</packaging>
<!--工程的版本号。在 artifact 的仓库中,它用来区分不同的版本-->
<version>1.0-SNAPSHOT</version>
    
<name>helloworld</name>
<url>http://maven.apache.org</url>

<!--properties标签很重要,它定义了一些关于pom.xml的变量和其属性值-->   
<!--配置依赖时,引用了这个变量,引用方法是“${junit.version}”.这种方式,在系统升级版本号、并配置父子项目(parent project)时,对我们非常有帮助,可以不用修改dependencies依赖,而直接修改properties里的值就可以了,非常方便!-->
<properties>
<project.build.sourceencoding>UTF-8</project.build.sourceencoding>
<junit.version>4.12</junit.version>
</properties>
    
<dependencies>
  <dependency>
    <groupid>junit</groupid>
    <artifactid>junit</artifactid>
    <version>3.8.1或${junit.version}</version>  
    <scope>test</scope>
  </dependency>
</dependencies>
 
</project>

更具体的标签注释

  • 大项目一般会分成几个子项目。在这种情况下,每个子项目就会有自己的 POM 文件,然后它们会有一个共同的父项目。这样只要构建父项目就能够构建所有的子项目了。子项目的 POM 会继承父项目的 POM。
    • 另外,所有的 POM都继承了一个 Super-POM。Super-POM 设置了一些默认值,比如默认的目录结构,默认的插件等等,它遵循了惯例优于配置的原则。

Maven插件

  • 这篇文章中,我们用了 mvn archetype:generate 命令来生成一个项目。archetype 是一个插件的名字,generate是目标(goal)的名字。这个命令的意思是告诉 maven 执行 archetype 插件的 generate 目标。插件目标通常会写成 pluginId:goalId

  • 一个目标是一个工作单元,而插件则是一个或者多个目标的集合。比如说Jar插件,Compiler插件,Surefire插件等。从看名字就能知道,Jar 插件包含建立Jar文件的目标, Compiler 插件包含编译源代码和单元测试代码的目标。Surefire 插件的话,则是运行单元测试。

  • 看到这里,估计你能明白了,mvn 本身不会做太多的事情,它不知道怎么样编译或者怎么样打包。它把构建的任务交给插件去做。插件定义了常用的构建逻辑,能够被重复利用。这样做的好处是,一旦插件有了更新,那么所有的 maven 用户都能得到更新。

Maven生命周期

  • 这篇文章中,我们用的第二个命令是:mvn package。这里的 package 是一个maven的生命周期阶段 (lifecycle phase )。生命周期指项目的构建过程,它包含了一系列的有序的阶段 (phase),而一个阶段就是构建过程中的一个步骤。

  • 那么生命周期阶段和上面说的插件目标之间是什么关系呢?插件目标可以绑定到生命周期阶段上。一个生命周期阶段可以绑定多个插件目标。当 maven 在构建过程中逐步的通过每个阶段时,会执行该阶段所有的插件目标。

  • maven 能支持不同的生命周期,但是最常用的是默认的Maven生命周期 (default Maven lifecycle )。如果你没有对它进行任何的插件配置或者定制的话,那么上面的命令 mvn package 会依次执行默认生命周期中直到包括 package 阶段前的所有阶段的插件目标:

process-resources 阶段:resources:resources

compile 阶段:compiler:compile

process-classes 阶段:(默认无目标)

process-test-resources 阶段:resources:testResources

test-compile 阶段:compiler:testCompile

test 阶段:surefire:test

prepare-package 阶段:(默认无目标)

package 阶段:jar:jar

Maven依赖管理

  • 之前我们说过,maven 坐标能够确定一个项目。换句话说,我们可以用它来解决依赖关系。在 POM 中,依赖关系是在 dependencies 部分中定义的。在上面的 POM 例子中,我们用 dependencies 定义了对于 junit 的依赖:

Xml 代码

<dependencies> 
    <dependency> 
      <groupid>junit</groupid> 
      <artifactid>junit</artifactid> 
      <version>3.8.1</version> 
      <scope>test</scope> 
    </dependency> 
  </dependencies>

那这个例子很简单,但是实际开发中我们会有复杂得多的依赖关系,因为被依赖的 jar 文件会有自己的依赖关系。那么我们是不是需要把那些间接依赖的 jar 文件也都定义在POM中呢?答案是不需要,因为 maven 提供了传递依赖的特性。

  • POM 的 dependencies 部分中,scope 决定了依赖关系的适用范围。我们的例子中 junitscopetest,那么它只会在执行 compiler:testCompile and surefire:test目标的时候才会被加到 classpath 中,在执行 compiler:compile 目标时是拿不到 junit 的。

传递依赖 与 排除依赖

  • 传递依赖:如果我们的项目引用了一个Jar包,而该Jar包又引用了其他Jar包,那么在默认情况下项目编译时,Maven会把直接引用和间接引用的Jar包都下载到本地。

  • 排除依赖:如果我们只想下载直接引用的Jar包,那么需要在pom.xml中做如下配置:(将需要排除的Jar包的坐标写在中)

    <exclusions>
       <exclusion>
          <groupId>cn.missbe.web.search</groupId>
          <artifactId>resource-search</artifactId>
          <packaging>pom</packaging>
          <version>1.0-SNAPSHOT</version>
       </exclusion>
    </exclusions>
    

依赖范围scope

在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。

  • compile :默认范围,用于编译
  • provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath
  • runtime: 在执行时需要使用
  • test: 用于test任务时使用
  • system: 需要外在提供相应的元素。通过systemPath来取得
  • systemPath: 仅用于范围为system。提供相应的路径
  • optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用

依赖冲突

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

  • 短路优先

    本项目——>A.jar——>B.jar——>X.jar
    本项目——>C.jar——>X.jar
    若本项目引用了A.jar,A.jar又引用了B.jar,B.jar又引用了X.jar,并且C.jar也引用了X.jar。

    在此时,Maven只会引用引用路径最短的Jar。

  • 声明优先

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

Maven库

  • Maven远程库: 如国内镜像站

  • Maven本地库:C:\Users\username.m2\repository

    • 本地库是指 maven 下载了插件或者 jar 文件后存放在本地机器上的拷贝。当 maven 查找需要的 jar 文件时,它会先在本地库中寻找,只有在找不到的情况下,才会去远程库中找。

    • 不是所有的 jar 文件都是可以从默认的远程库下载的,比如说我们自己开发的项目。

      • 运行下面的命令能把我们的 helloworld 项目安装到本地库:

        mvn install
        
      • 一旦一个项目被安装到了本地库后,你别的项目就可以通过 maven 坐标和这个项目建立依赖关系。比如如果我现在有一个新项目需要用到 helloworld,那么在运行了上面的 mvn install 命令后,我就可以如下所示来建立依赖关系:

        Xml 代码

        <dependency>
              <groupid>com.mycompany.helloworld</groupid>
              <artifactid>helloworld</artifactid>
              <version>1.0-SNAPSHOT</version>
            </dependency>
        

版权声明:本文为iterationjia原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/iterationjia/p/14481097.html