maven基础入门

197 阅读38分钟

1. Settings配置

settings.xml用来配置maven项目中的各种参数文件,包括本地仓库、远程仓库、私服、认证等信息。

1.1 配置概述

1.1.1 全局settings、用户setting、pom的区别

  • 全局 settings.xml 是 maven 的全局配置文件,一般位于${maven.home}/conf/settings.xml,即maven文件夹下的conf中。
  • 用户 setting是maven的用户配置文件,一般位于${user.home}/.m2/settings.xml,即每位用户都有一份配置文件。
  • pom.xml 文件是项目配置文件,一般位于项目根目录下或子目录下。

配置优先级从高到低:pom.xml > 本地 settings > 全局 settings

如果这些文件同时存在,在应用配置时,会合并它们的内容,如果有重复的配置,优先级高的配置会覆盖优先级低的。

1.1.2 仓库【重要】

如前言所述,我们依赖的外部服务是需要有地方进行存储的,而存储的地方就称之为仓库。其中仓库又分为本地仓库、中央仓库、镜像仓库、私服。

其对应关系为:

5c2ca7834b8a4e45a4245191dcb9e4ba~tplv-k3u1fbpfcp-zoom-1.image

(1)本地仓库

当项目在本地编译或运行时,直接加载本地的依赖服务无疑是最快的。默认情况下,不管在Window还是Linux下,每个用户在自己用户目录下都有一个路径名为.m2/repository/的仓库目录。

而原始的本地仓库是为空的,因此maven需要知道一个网络上的仓库,在本地仓库不存在时前往下载网络上的仓库,也就是远程仓库。

(2)中央仓库

当maven未配置时,会默认请求maven的中央仓库,中央仓库包含了这个世界上绝大多数流行的开源java构件,以及源码、作者信息、SCM,信息、许可证信息等,每个月这里都会接受全世界java程序员大概1亿次的访问,它对全世界java开发者的贡献由此可见一斑。

但是由于最常见的例如网络原因等,国外的中央仓库使用起来并不顺利,因此就有了下载地址为国内的中央仓库,也就是镜像仓库。

(3)镜像仓库

总结来说,镜像仓库就是将国外的中心仓库复制一份到国内,这样一来下载速度以及访问速度都将很快。

(4)私服

一般来说中央仓库或者镜像仓库都能满足我们的需求,但是当我们在公司内合作开发代码时,可能因为系统保密性原因,有一些其他同事开发的外部依赖只希望能够被本公司的人使用,而如果上传到镜像仓库则保密性就不复存在了。因此私服最主要的功能时存储一些公司内部不希望被公开的依赖服务。

1.2 settings配置详解

settings.xml配置了本地全局maven的相关配置。

以下是一份seetings.xml的文件配置顶级元素。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                          https://maven.apache.org/xsd/settings-1.0.0.xsd">
      <localRepository>
      <interactiveMode>
      <usePluginRegistry>
      <offline>
      <pluginGroups>
      <servers>
      <mirrors>
      <proxies>
      <profiles>
      <activeProfiles>
</settings>

1.2.1 localRepository

用来标识本地仓库的位置

D:/Maven/Repository

1.2.2 interactiveMode

maven 是否需要和用户交互以获得输入。默认为true。

true

1.2.3 usePluginRegistry

maven 是否需要使用 plugin-registry.xml 文件来管理插件版本。

false

1.2.4 offline

用来标识是否以离线模式运营maven。

当系统不能联网时,可以通过次配置来离线运行。

false

1.2.5 servers

当使用maven私服时,某些私服需要配置认证信息,需要在此处填写相应的配置。之所以不写在pom.xml中是因为一般项目在上传至代码仓库时同样会将pom.xml上传,而setting.xml一般位于用户本地,因此相对比较安全。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      https://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <!--配置服务端的一些设置。一些设置如安全证书不应该和pom.xml一起分发。这种类型的信息应该存在于构建服务器上的settings.xml文件中。 -->
  <servers>
    <!--服务器元素包含配置服务器时需要的信息 -->
    <server>
      <!--这是server的id(注意不是用户登陆的id),该id与distributionManagement中repository元素的id相匹配。 -->
      <id>server001</id>
      <!--鉴权用户名。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。 -->
      <username>my_login</username>
      <!--鉴权密码 。鉴权用户名和鉴权密码表示服务器认证所需要的登录名和密码。密码加密功能已被添加到2.1.0 +。详情请访问密码加密页面 -->
      <password>my_password</password>
      <!--鉴权时使用的私钥位置。和前两个元素类似,私钥位置和私钥密码指定了一个私钥的路径(默认是${user.home}/.ssh/id_dsa)以及如果需要的话,一个密语。将来passphrase和password元素可能会被提取到外部,但目前它们必须在settings.xml文件以纯文本的形式声明。 -->
      <privateKey>${usr.home}/.ssh/id_dsa</privateKey>
      <!--鉴权时使用的私钥密码。 -->
      <passphrase>some_passphrase</passphrase>
      <!--文件被创建时的权限。如果在部署的时候会创建一个仓库文件或者目录,这时候就可以使用权限(permission)。这两个元素合法的值是一个三位数字,其对应了unix文件系统的权限,如664,或者775。 -->
      <filePermissions>664</filePermissions>
      <!--目录被创建时的权限。 -->
      <directoryPermissions>775</directoryPermissions>
    </server>
  </servers>
  ...
</settings>

1.2.6 mirrors【重要】

用来配置相应的镜像仓库。

如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。用过Maven的都知道,国外的中央仓库因为网络原因用起来太慢了,所以选择一个国内的镜像就很有必要,我推荐国内的阿里云镜像。 阿里云镜像:配置很简单,修改conf文件夹下的settings.xml文件,添加如下镜像配置:

<mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>        
    </mirror> 
    <mirror>
      <id>alimaven1</id>
      <name>aliyun maven1</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>*</mirrorOf>        
    </mirror>
</mirrors>

其中id与name用来标识唯一的仓库,url为镜像仓库地址,mirrorOf用来匹配当请求什么仓库依赖时使用该镜像。

这里介绍下<mirrorOf>配置的各种选项

  • <mirrorOf>*<mirrorOf>:匹配所有远程仓库。
  • <mirrorOf>external:*<mirrorOf>:匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。
  • <mirrorOf>repo1,repo2<mirrorOf>:匹配仓库repo1h和repo2,使用逗号分隔多个远程仓库。
  • <mirrorOf>*,!repo1<mirrorOf>:匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。

需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。

此外, maven 读取mirror 配置是 从上往下读取的,因此谨慎配置<mirrorOf>*<mirrorOf>,因为如果第一个镜像仓库配置了如此标志,那么如果该仓库即使不存在对应依赖也不会向下游查询。

1.2.7 proxies

用来配置代理。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      https://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <proxies>
    <!--代理元素包含配置代理时需要的信息 -->
    <proxy>
      <!--代理的唯一定义符,用来区分不同的代理元素。 -->
      <id>myproxy</id>
      <!--该代理是否是激活的那个。true则激活代理。当我们声明了一组代理,而某个时候只需要激活一个代理的时候,该元素就可以派上用处。 -->
      <active>true</active>
      <!--代理的协议。 协议://主机名:端口,分隔成离散的元素以方便配置。 -->
      <protocol>http</protocol>
      <!--代理的主机名。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
      <host>proxy.somewhere.com</host>
      <!--代理的端口。协议://主机名:端口,分隔成离散的元素以方便配置。 -->
      <port>8080</port>
      <!--代理的用户名,用户名和密码表示代理服务器认证的登录名和密码。 -->
      <username>proxyuser</username>
      <!--代理的密码,用户名和密码表示代理服务器认证的登录名和密码。 -->
      <password>somepassword</password>
      <!--不该被代理的主机名列表。该列表的分隔符由代理服务器指定;例子中使用了竖线分隔符,使用逗号分隔也很常见。 -->
      <nonProxyHosts>*.google.com|ibiblio.org</nonProxyHosts>
    </proxy>
  </proxies>
  ...
</settings>

1.2.8 profiles【重要】

根据环境参数来调整构建配置的列表。用于定义一组profile

seetings中的profile是 pom.xml 中 profile 元素的裁剪版本

它包含了idactivationrepositoriespluginRepositories 和 properties 元素。这里的 profile 元素只包含这五个子元素是因为这里只关心构建系统这个整体(这正是 settings.xml 文件的角色定位),而非单独的项目对象模型设置。如果一个 settings.xml 中的 profile 被激活,它的值会覆盖任何其它定义在 pom.xml 中带有相同 id 的 profile

(1)repositories

定义了一组远程仓库的列表,当该属性对应的profile被激活时,会使用该远程仓库。

<repositories>
  <!--包含需要连接到远程仓库的信息 -->
  <repository>
    <!--远程仓库唯一标识 -->
    <id>codehausSnapshots</id>
    <!--远程仓库名称 -->
    <name>Codehaus Snapshots</name>
    <!--如何处理远程仓库里发布版本的下载 -->
    <releases>
      <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
      <enabled>false</enabled>
      <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。 -->
      <updatePolicy>always</updatePolicy>
      <!--当Maven验证构件校验文件失败时该怎么做-ignore(忽略),fail(失败),或者warn(警告)。 -->
      <checksumPolicy>warn</checksumPolicy>
    </releases>
    <!--如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的策略。例如,可能有人会决定只为开发目的开启对快照版本下载的支持。参见repositories/repository/releases元素 -->
    <snapshots>
      <enabled />
      <updatePolicy />
      <checksumPolicy />
    </snapshots>
    <!--远程仓库URL,按protocol://hostname/path形式 -->
    <url>http://snapshots.maven.codehaus.org/maven2</url>
    <!--用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。 -->
    <layout>default</layout>
  </repository>
</repositories>
(2)properties

定义了一组拓展属性,当对应的profile被激活时该属性有效。

<!--
  1. env.X: 在一个变量前加上"env."的前缀,会返回一个shell环境变量。例如,"env.PATH"指代了$path环境变量(在Windows上是%PATH%)。
  2. project.x:指代了POM中对应的元素值。例如: <project><version>1.0</version></project>通过${project.version}获得version的值。
  3. settings.x: 指代了settings.xml中对应元素的值。例如:<settings><offline>false</offline></settings>通过 ${settings.offline}获得offline的值。
  4. java System Properties: 所有可通过java.lang.System.getProperties()访问的属性都能在POM中使用该形式访问,例如 ${java.home}。
  5. x: 在<properties/>元素中,或者外部文件中设置,以${someVar}的形式使用。
 -->
<properties>
  <user.install>${user.home}/our-project</user.install>
</properties>
(3)id

全局唯一标识,如果一个 settings.xml 中的 profile 被激活,它的值会覆盖任何其它定义在 pom.xml 中带有相同 id 的 profile

(4)pluginRepositories

同repositories差不多,不过该标签定义的是插件的远程仓库。

(5)activation

触发激活该profile的条件。

<activation>
    <!--profile默认是否激活的标识 -->
    <activeByDefault>false</activeByDefault>
    <!--当匹配的jdk被检测到,profile被激活。例如,1.4激活JDK1.4,1.4.0_2,而!1.4激活所有版本不是以1.4开头的JDK。 -->
    <jdk>1.5</jdk>
    <!--当匹配的操作系统属性被检测到,profile被激活。os元素可以定义一些操作系统相关的属性。 -->
    <os>
        <!--激活profile的操作系统的名字 -->
        <name>Windows XP</name>
        <!--激活profile的操作系统所属家族(如 'windows') -->
        <family>Windows</family>
        <!--激活profile的操作系统体系结构 -->
        <arch>x86</arch>
        <!--激活profile的操作系统版本 -->
        <version>5.1.2600</version>
    </os>
    <!--如果Maven检测到某一个属性(其值可以在POM中通过${name}引用),其拥有对应的name = 值,Profile就会被激活。如果值字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段 -->
    <property>
        <!--激活profile的属性的名称 -->
        <name>mavenVersion</name>
        <!--激活profile的属性的值 -->
        <value>2.0.3</value>
    </property>
    <!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。missing检查文件是否存在,如果不存在则激活profile。另一方面,exists则会检查文件是否存在,如果存在则激活profile。 -->
    <file>
        <!--如果指定的文件存在,则激活profile。 -->
        <exists>${basedir}/file2.properties</exists>
        <!--如果指定的文件不存在,则激活profile。 -->
        <missing>${basedir}/file1.properties</missing>
    </file>
</activation>

1.2.9 ActiveProfiles

在运行时手工激活的profile。

该元素包含了一组 activeProfile 元素,每个 activeProfile 都含有一个 profile id。任何在 activeProfile 中定义的 profile id,不论环境设置如何,其对应的 profile 都会被激活。如果没有匹配的 profile,则什么都不会发生。

<activeProfiles>
    <!-- 要激活的profile id -->
    <activeProfile>env-test</activeProfile>
</activeProfiles>

1.2.10 激活profile的三种方式【重要】

上面有提到了两种激活的profile的方式,还有一种可以通过命令行激活profile。

(1)通过ActiveProfiles激活

如题1.2.9 可以同时激活多个profile。

(2)通过activation结果

如题1.2.8 (5)

(3)通过命令行的方式激活

也是我们经常使用的方式,例如:

mvn -P 

我们可以通过在pom.xml或setting.xml中指定不同环境的profile,在编译构建不同的项目时,通过上述的命令行方式激活对应的profIle。例如在开发环境下:

mvn package -P dev 

可以打包开环环境下的项目。

1.3 Q&A

1.3.1 mirrors与repositories的关系【重要】

从上文可以看到,repository标签与mirror标签都定义了一个远程仓库的位置,那么当一个依赖同时存在于两个仓库时,会先加载那个依赖呢?

这里需要阐述一下maven加载真正起作用的repository的步骤,

  1. 首先获取pom.xml中repository的集合,然后获取setting.xml中mirror中元素。
  2. 如果repository的id和mirror的mirrorOf的值相同,则该mirror替代该repository。
  3. 如果该repository找不到对应的mirror,则使用其本身。
  4. 依此可以得到最终起作用的repository集合。可以理解mirror是复写了对应id的repository。

mirror相当于一个拦截器,会拦截被mirrorOf匹配到的repository,匹配原则参照 1.2.6 ,在匹配到后,会用mirror里定义的url替换到repository。

没有配置mirror

48ba84c5af754c698e8d4a9ee0fbbe8c~tplv-k3u1fbpfcp-zoom-1.image

配置了mirror

42759bcf285b4a9f8fec4c5e6ee2ff98~tplv-k3u1fbpfcp-zoom-1.image

2. Pom.xml详解

上章中setting.xml定义了某个环境下全局项目的相关依赖配置,而pom.xml则具体定义了某一个项目中的依赖配置。

2.1 pom元素

2.1.1 基本信息

<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>
    <!-- 公司或者组织的唯一标志,也是打包成jar包路径的依据 -->
    <!-- 例如com.companyname.project-group,maven打包jar包的路径:/com/companyname/project-group -->
    <groupId>com.companyname.project-group</groupId><!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
    <artifactId>project</artifactId><!-- 项目当前版本,格式为:主版本.次版本.增量版本-限定版本号 -->
    <version>1.0</version><!--项目产生的构件类型,
    jar、war主要用来标识项目打包出的服务是jar包还是war包 
    pom一般用作多moudle的项目中 顶层的pom用来指定子moudle中需要依赖的版本 详见2.1.3 -->
    <packaging>jar</packaging><!--定义了本项目的名称与example的网址 -->
    <name>itoken dependencies</name>
    <url>www.funtl.com</url>
</project>

基本信息都比较易懂,主要定义了本项目的相关配置说明,例如唯一坐标、版本、项目介绍等。

2.1.2 dependencies【重要】

(1)dependencies

本元素定义了项目中所需要的相关依赖信息,也是最重要的元素之一。

<!--该元素描述了项目相关的所有依赖。 这些依赖自动从项目定义的仓库中下载 -->
<dependencies>
    <dependency>
        <!------------------- 依赖坐标 ------------------->
        <!--依赖项目的坐标三元素:groupId + artifactId + version -->
        <!--其中三要素的来源就是2.1.1中别人定义好的相关信息 -->
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-artifact</artifactId>
        <version>3.8.1</version><!------------------- 依赖传递 ------------------->
        <!--依赖排除,即告诉maven只依赖指定的项目,不依赖该项目的这些依赖。此元素主要用于解决版本冲突问题 -->
        <exclusions>
            <exclusion>
                <artifactId>spring-core</artifactId>
                <groupId>org.springframework</groupId>
            </exclusion>
        </exclusions>
        <!-- 可选依赖,用于阻断依赖的传递性。如果在项目B中把C依赖声明为可选,那么依赖B的项目中无法使用C依赖 -->
        <optional>true</optional><!------------------- 依赖范围 ------------------->
        <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来
            - compile:默认范围,适用于所有阶段,会随着项目一起发布;  
            - runtime: 在执行时需要使用,如JDBC驱动,适用运行和测试阶段,不同于例如fastjson,需要在编译时使用;   
            - test: 只在测试时使用,用于编译和运行测试代码,例如junit,不同于junit,在发布时并不需要;    
            - optional: 当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用 -->
        <scope>test</scope>
    </dependency>
</dependencies>

(2)如何解决依赖传递问题或jar包版本冲突问题

解决上述问题一般有两种方式:

  • 当我们作为依赖服务提供者时,可以通过<optional>标签排除掉不想被传递的服务。
<!-- Project A -->
<project>
    ...
    <dependencies>
        <!-- declare the dependency to be set as optional -->
        <dependency>
            <groupId>sample.ProjectB</groupId>
            <artifactId>Project-B</artifactId>
            <version>1.0</version>
            <optional>true</optional> 
        </dependency>
    </dependencies>
</project>

我们的A服务中引用了外部的依赖B服务,此时有A -> B,在别人引用我们时有C -> A ->B,若此时我们A在提供对外服务时不想让别人依赖B服务,可以在引用B时添加<optional>标签为true,这样带C依赖于A时并不会引入B。如果C在此时想要使用B的相关服务,需要在C的pom中显示的调用B的相关服务。

  • 当我们作为依赖服务使用者时,可以通过<exclusions>来去除掉我们依赖包中所不想依赖的其他服务。

如果此时我们的A服务依赖于B服务,B服务依赖于C服务,则有A ->B ->C,因为某种原因例如jar包冲突,我们在A中并不想依赖于C服务的版本,可以在调用B服务时去除掉C的相关依赖,然后自己再在A中使用C的相关版本。

<project>
    ...
    <dependencies>
        <dependency>
            <groupId>sample.ProjectB</groupId>
            <artifactId>Project-B</artifactId>
            <version>1.0</version>
            <exclusions>
                <exclusion>
                    <!-- 排除掉B中C的相关依赖 -->
                    <groupId>sample.ProjectC</groupId>
                    <artifactId>Project-C</artifactId>
                </exclusion>
            </exclusions> 
        </dependency>
        <!-- 自己引用C的相关版本 -->
        <dependency>
            <groupId>sample.ProjectC</groupId>
            <artifactId>Project-C</artifactId>
            <version>2.0</version>
        </dependency>
    </dependencies>
</project>

2.1.3 <dependencyManagement>

当一个服务中存在有多个moudle时,每个子module都可能引用了相同的jar包,但是如果将版本维护到子module的pom中,当需要升级时需要修改所有的pom文件版本。maven提供了继承的方式来解决此问题。

<!--在父pom中定义子pom需要的相关依赖 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

在父pom的 <dependencyManagement> 中定义子pom需要的依赖及版本。

<!--在子pom中  如下定义了父pom中相关依赖信息 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.10.RELEASE</version>
    <relativePath/>
</parent><dependencies>
    <dependency>
        <!--因为引用了父pom 所以可以不指定版本 maven会自动去父pom中查找指定版本 此处为1.0.0 -->
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
    </dependency>
</dependencies>

当我们的pom中有定义父pom的元素后,可以在指定需要的依赖时不指定其版本,maven会帮我们去父pom中查找相关的版本信息。

2.1.4 properties

properties主要用来定义常量,通过${value}来使用。

<!--配置依赖版本-->
<properties>
    <!-- Environment Settings -->
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!-- Spring cloud Settings   -->
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <spring-boot-admin.version>2.0.1</spring-boot-admin.version>
    <zipkin.version>2.10.1</zipkin.version>
</properties><dependencies>
    <!--spring cloud-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <!--zipkin-->
    <dependency>
        <groupId>io.zipkin.java</groupId>
        <artifactId>zipkin</artifactId>
        <version>${zipkin.version}</version>
    </dependency>
</dependencies>

此外,maven还通过约定大于配置的方式定义了一些常用的属性。

属性定义
${basedir}存放pom.xml和所有的子目录
${basedir}/src/main/java项目的java源代码
${basedir}/src/main/resources项目的资源,比如说property文件,springmvc.xml
${basedir}/src/main/webapp/WEB-INFweb应用文件目录,web项目的信息,比如存放web.xml、本地图片、jsp视图页面
${basedir}/target打包输出目录
${project.version}项目版本
${project.groupId}项目groupid

2.1.5 resources

详见 3.3maven-resources-plugin

2.1.6 profile

与setting.xml中profile所不同的是(参照1.2.8),pom中的profile有着更多的标签来描述一组环境。从作用上来区分的话,一般setting.xml用来标识不同的远程仓库,而pom中的profile一般用来标识当前项目属于什么环境,如下是一组常见的pom中的profiles。

<profiles>
    <profile>
        <id>dev</id>
        <!--激活条件 其中默认为该profile 更多激活条件可以参考1.2.8 -->
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <!--当此profile被激活时,会将 project.active 的属性赋值为dev -->
        <properties>
            <project.active>dev</project.active>
        </properties>
    </profile>
    <profile>
        <id>test</id>
        <!--当此profile被激活时,会将 project.active 的属性赋值为test -->
        <properties>
            <project.active>test</project.active>
        </properties>
    </profile>
</profiles><resources>
    <resource>
        <!--根据不同的环境 project.active 取得不同的值 从而会将不同的环境下的yaml或properties文件编译进项目中 达到只需要在编译时指定环境变量即可 不用每次都要修改配置文件 -->
        <directory>src/main/${project.active}</directory>
        <filtering>true</filtering>
        <includes>
            <include>**/*.fxml</include>
        </includes>
    </resource>
</resources>

此外,一般通过 mvn -P dev/beta/pre/product 命令来激活不同的环境,也可以通过其他的方式来激活profile,详见1.2.10。

当然,pom中的profile不止有指定编译环境的功能,同样也可以指定远程仓库等其他功能。

2.1.7 modules

当我们项目中有多个模块时,如果我们要单独打包的话需要在每一个模块都执行对应的maven命令,但是通过<modules>标签可以将子服务或平级服务进行聚合,只需要打包该服务,也就会将其对应的子模块同时打包。

<modules>
    <!-- 引入子模块所在的相对目录 -->
    <module>springmybatis</module>
    <!-- 引入同级模块所在的相对目录 -->
    <module>../utils</module>
 </modules>

2.1.8 样例

<?xml version="1.0" encoding="utf-8"?>
 
<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.0http://maven.apache.org/maven-v4_0_0.xsd">  
  <!--父项目的坐标。如果项目中没有规定某个元素的值,
那么父项目中的对应值即为项目的默认值。 
坐标包括group ID,artifact ID和 version。-->  
  <parent> 
    <!--被继承的父项目的构件标识符-->  
    <artifactId/>  
    <!--被继承的父项目的全球唯一标识符-->  
    <groupId/>  
    <!--被继承的父项目的版本-->  
    <version/> 
  </parent>  
  <!--声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此,
但它仍然是必不可少的,这是为了当Maven引入了新的特性或者其他模型变更的时候,
确保稳定性。-->  
  <modelVersion>4.0.0</modelVersion>  
  <!--项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。
并且构建时生成的路径也是由此生成, 如com.mycompany.app生成的相对路径为:
/com/mycompany/app-->  
  <groupId>cn.missbe.web</groupId>  
  <!-- 构件的标识符,它和group ID一起唯一标识一个构件。换句话说,
你不能有两个不同的项目拥有同样的artifact ID和groupID;在某个 
特定的group ID下,artifact ID也必须是唯一的。构件是项目产生的或使用的一个东西,
Maven为项目产生的构件包括:JARs,源码,二进制发布和WARs等。-->  
  <artifactId>search-resources</artifactId>  
  <!--项目产生的构件类型,例如jar、war、ear、pom。插件可以创建
他们自己的构件类型,所以前面列的不是全部构件类型-->  
  <packaging>war</packaging>  
  <!--项目当前版本,格式为:主版本.次版本.增量版本-限定版本号-->  
  <version>1.0-SNAPSHOT</version>  
  <!--项目的名称, Maven产生的文档用-->  
  <name>search-resources</name>  
  <!--项目主页的URL, Maven产生的文档用-->  
  <url>http://www.missbe.cn</url>  
  <!-- 项目的详细描述, Maven 产生的文档用。  当这个元素能够用HTML格式描述时
(例如,CDATA中的文本会被解析器忽略,就可以包含HTML标 签), 
不鼓励使用纯文本描述。如果你需要修改产生的web站点的索引页面,
你应该修改你自己的索引页文件,而不是调整这里的文档。-->  
  <description>A maven project to study maven.</description>  
  <!--描述了这个项目构建环境中的前提条件。-->  
  <prerequisites> 
    <!--构建该项目或使用该插件所需要的Maven的最低版本-->  
    <maven/> 
  </prerequisites>  
  <!--构建项目需要的信息-->  
  <build> 
    <!--该元素设置了项目源码目录,当构建项目的时候,
构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。-->  
    <sourceDirectory/>  
    <!--该元素设置了项目脚本源码目录,该目录和源码目录不同:
绝大多数情况下,该目录下的内容 会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。-->  
    <scriptSourceDirectory/>  
    <!--该元素设置了项目单元测试使用的源码目录,当测试项目的时候,
构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。-->  
    <testSourceDirectory/>  
    <!--被编译过的应用程序class文件存放的目录。-->  
    <outputDirectory/>  
    <!--被编译过的测试class文件存放的目录。-->  
    <testOutputDirectory/>  
    <!--使用来自该项目的一系列构建扩展-->  
    <extensions> 
      <!--描述使用到的构建扩展。-->  
      <extension> 
        <!--构建扩展的groupId-->  
        <groupId/>  
        <!--构建扩展的artifactId-->  
        <artifactId/>  
        <!--构建扩展的版本-->  
        <version/> 
      </extension> 
    </extensions>  
    <!--这个元素描述了项目相关的所有资源路径列表,例如和项目相关的属性文件,
这些资源被包含在最终的打包文件里。-->  
    <resources> 
      <!--这个元素描述了项目相关或测试相关的所有资源路径-->  
      <resource> 
        <!-- 描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。举个例 子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven /messages。
然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。-->  
        <targetPath/>  
        <!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,
文件在filters元素里列出。-->  
        <filtering/>  
        <!--描述存放资源的目录,该路径相对POM路径-->  
        <directory/>  
        <!--包含的模式列表,例如**/*.xml.-->  
        <includes/>  
        <!--排除的模式列表,例如**/*.xml-->  
        <excludes/> 
      </resource> 
    </resources>  
    <!--这个元素描述了单元测试相关的所有资源路径,例如和单元测试相关的属性文件。-->  
    <testResources> 
      <!--这个元素描述了测试相关的所有资源路径,参见build/resources/resource元素的说明-->  
      <testResource> 
        <targetPath/>
        <filtering/>
        <directory/>
        <includes/>
        <excludes/> 
      </testResource> 
    </testResources>  
    <!--构建产生的所有文件存放的目录-->  
    <directory/>  
    <!--产生的构件的文件名,默认值是${artifactId}-${version}。-->  
    <finalName/>  
    <!--当filtering开关打开时,使用到的过滤器属性文件列表-->  
    <filters/>  
    <!--子项目可以引用的默认插件信息。该插件配置项直到被引用时才会被解析或绑定到生命周期。
给定插件的任何本地配置都会覆盖这里的配置-->  
    <pluginManagement> 
      <!--使用的插件列表 。-->  
      <plugins> 
        <!--plugin元素包含描述插件所需要的信息。-->  
        <plugin> 
          <!--插件在仓库里的group ID-->  
          <groupId/>  
          <!--插件在仓库里的artifact ID-->  
          <artifactId/>  
          <!--被使用的插件的版本(或版本范围)-->  
          <version/>  
          <!--是否从该插件下载Maven扩展(例如打包和类型处理器),由于性能原因,
只有在真需要下载时,该元素才被设置成enabled。-->  
          <extensions/>  
          <!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。-->  
          <executions> 
            <!--execution元素包含了插件执行需要的信息-->  
            <execution> 
              <!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标-->  
              <id/>  
              <!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段-->  
              <phase/>  
              <!--配置的执行目标-->  
              <goals/>  
              <!--配置是否被传播到子POM-->  
              <inherited/>  
              <!--作为DOM对象的配置-->  
              <configuration/> 
            </execution> 
          </executions>  
          <!--项目引入插件所需要的额外依赖-->  
          <dependencies> 
            <!--参见dependencies/dependency元素-->  
            <dependency>......</dependency> 
          </dependencies>  
          <!--任何配置是否被传播到子项目-->  
          <inherited/>  
          <!--作为DOM对象的配置-->  
          <configuration/> 
        </plugin> 
      </plugins> 
    </pluginManagement>  
    <!--使用的插件列表-->  
    <plugins> 
      <!--参见build/pluginManagement/plugins/plugin元素-->  
      <plugin> 
        <groupId/>
        <artifactId/>
        <version/>
        <extensions/>  
        <executions> 
          <execution> 
            <id/>
            <phase/>
            <goals/>
            <inherited/>
            <configuration/> 
          </execution> 
        </executions>  
        <dependencies> 
          <!--参见dependencies/dependency元素-->  
          <dependency>......</dependency> 
        </dependencies>  
        <goals/>
        <inherited/>
        <configuration/> 
      </plugin> 
    </plugins> 
  </build>  
  <!--模块(有时称作子项目) 被构建成项目的一部分。
列出的每个模块元素是指向该模块的目录的相对路径-->  
  <modules/>  
  <!--发现依赖和扩展的远程仓库列表。-->  
  <repositories> 
    <!--包含需要连接到远程仓库的信息-->  
    <repository> 
      <!--如何处理远程仓库里发布版本的下载-->  
      <releases> 
        <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->  
        <enabled/>  
        <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。-->  
        <updatePolicy/>  
        <!--当Maven验证构件校验文件失败时该怎么做:ignore(忽略),fail(失败),或者warn(警告)。-->  
        <checksumPolicy/> 
      </releases>  
      <!-- 如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,
POM就可以在每个单独的仓库中,为每种类型的构件采取不同的 策略。
例如,可能有人会决定只为开发目的开启对快照版本下载的支持。
参见repositories/repository/releases元素 -->  
      <snapshots> 
        <enabled/>
        <updatePolicy/>
        <checksumPolicy/> 
      </snapshots>  
      <!--远程仓库唯一标识符。可以用来匹配在settings.xml文件里配置的远程仓库-->  
      <id>banseon-repository-proxy</id>  
      <!--远程仓库名称-->  
      <name>banseon-repository-proxy</name>  
      <!--远程仓库URL,按protocol://hostname/path形式-->  
      <url>http://192.168.1.169:9999/repository/</url>  
      <!-- 用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然 而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。-->  
      <layout>default</layout> 
    </repository> 
  </repositories>  
  <!--发现插件的远程仓库列表,这些插件用于构建和报表-->  
  <pluginRepositories> 
    <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素-->  
    <pluginRepository>......</pluginRepository> 
  </pluginRepositories>  
  <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。
它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。-->  
  <dependencies> 
    <dependency> 
      <!--依赖的group ID-->  
      <groupId>org.apache.maven</groupId>  
      <!--依赖的artifact ID-->  
      <artifactId>maven-artifact</artifactId>  
      <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。-->  
      <version>3.8.1</version>  
      <!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外
。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应,
 尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。
如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。-->  
      <type>jar</type>  
      <!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。
分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 JAR,
一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。-->  
      <classifier/>  
      <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。    
                - compile :默认范围,用于编译      
                - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath      
                - runtime: 在执行时需要使用      
                - test:    用于test任务时使用      
                - system: 需要外在提供相应的元素。通过systemPath来取得      
                - systemPath: 仅用于范围为system。提供相应的路径      
                - optional:   当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用-->  
      <scope>test</scope>  
      <!--仅供system范围使用。注意,不鼓励使用这个元素,
并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。
需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例如${java.home}。-->  
      <systemPath/>  
      <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。
即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题-->  
      <exclusions> 
        <exclusion> 
          <artifactId>spring-core</artifactId>  
          <groupId>org.springframework</groupId> 
        </exclusion> 
      </exclusions>  
      <!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。-->  
      <optional>true</optional> 
    </dependency> 
  </dependencies>  
  <!-- 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析,
而是当子项目声明一个依赖(必须描述group ID和 artifact ID信息),
如果group ID和artifact ID以外的一些信息没有描述,
则通过group ID和artifact ID 匹配到这里的依赖,并使用这里的依赖信息。-->  
  <dependencyManagement> 
    <dependencies> 
      <!--参见dependencies/dependency元素-->  
      <dependency>......</dependency> 
    </dependencies> 
  </dependencyManagement>  
  <!--项目分发信息,在执行mvn deploy后表示要发布的位置。
有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。-->  
  <distributionManagement> 
    <!--部署项目产生的构件到远程仓库需要的信息-->  
    <repository> 
      <!--是分配给快照一个唯一的版本号(由时间戳和构建流水号)?
还是每次都使用相同的版本号?参见repositories/repository元素-->  
      <uniqueVersion/>  
      <id>banseon-maven2</id>  
      <name>banseon maven2</name>  
      <url>file://${basedir}/target/deploy</url>  
      <layout/> 
    </repository>  
    <!--构件的快照部署到哪里?如果没有配置该元素,默认部署到repository元素配置的仓库,
参见distributionManagement/repository元素-->  
    <snapshotRepository> 
      <uniqueVersion/>  
      <id>banseon-maven2</id>  
      <name>Banseon-maven2 Snapshot Repository</name>  
      <url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url>  
      <layout/> 
    </snapshotRepository>  
    <!--部署项目的网站需要的信息-->  
    <site> 
      <!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置-->  
      <id>banseon-site</id>  
      <!--部署位置的名称-->  
      <name>business api website</name>  
      <!--部署位置的URL,按protocol://hostname/path形式-->  
      <url>scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web</url> 
    </site>  
    <!--项目下载页面的URL。如果没有该元素,用户应该参考主页。
使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。-->  
    <downloadUrl/>  
    <!-- 给出该构件在远程仓库的状态。不得在本地项目中设置该元素,
因为这是工具自动更新的。有效的值有:none(默认),
converted(仓库管理员从 Maven 1 POM转换过来),partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部 署),verified(被核实时正确的和最终的)。-->  
    <status/> 
  </distributionManagement>  
  <!--以值替代名称,Properties可以在整个POM中使用,也可以作为触发条件(见settings.xml配置文件里activation元素的说明)。格式是<name>value</name>。-->  
  <properties/> 
</project>

2. maven的依赖

2.1 maven的依赖范围

依赖范围对于编译classpath有效对于测试classpath有效对于运行时classpath有效例子
compileYYYspring-core
test-Y-Junit
providedYY-编译和测试有效,运行时无效,例如servlet-api
runtime-YYJDBC驱动,编译时用接口,运行时用具体实现
systemYY-对编译和测试classpath有效,但在运行时无效。使用该范围时,必须通过systemPath元素指定依赖的路径。
import引入DependencyManagement

import使用方法:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>other.pom.group.id</groupId>
            <artifactId>other-pom-artifact-id</artifactId>
            <version>SNAPSHOT</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>   
    </dependencies>
</dependencyManagement>

systemy依赖范围使用方法:

    <dependency>
        <groupId>javax.sql</groupId>
        <artifactId>jdbc-stdext</artifactId>
        <version>2.0</version>
        <scope>system</scope>
        <systemPath>${java.home}/lib/rt.jar</systemPath> <!--通过systemPath指定jar包路径-->
    </dependency>

2.2 什么是依赖传递

在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C。假设C依赖B,B依赖A,那么我们可以根据maven项目依赖的特征不难推出项目C也依赖A。

图片3.png

图片4.png

通过上面的图可以看到,我们的web项目直接依赖了spring-webmvc,而spring-webmvc依赖了sping-aop、spring-beans等。最终的结果就是在我们的web项目中间接依赖了spring-aop、spring-beans等。

依赖范围对传递依赖影响 下表中的纵向为 demo-a 中的scope,横向为 demo-b 中的 scope,中间的部分为 demo-c 传递到demo-a的scope,经过组合之后,一共得到了16个结果:

image.png

scopecompileruntimeprovidedtest
compilecompileruntime--
runtimeruntimeruntime--
providedprovidedprovided--
testtesttest--

我们把 demo-a 依赖 demo-b 称为直接依赖,demo-a 依赖 demo-c 称为间接依赖,来得出的最终结论为:

  • provided 与 test 范围不会向上传递。
  • compile 范围在向上传递的时候,间接依赖于直接依赖的范围一致。
  • runtime 范围与 compile 类似,区别在于直接依赖为compile时,间接依赖的范围依然是runtime

2.3 Maven依赖优先级

直接依赖:

比如项目有A有这样的依赖关系:A->B(1.0),A->B(2.0),后声明的依赖会覆盖先声明的依赖。最终A直接依赖B(2.0)

间接依赖:

  1. 路径最近者优先 比如项目有A有这样的依赖关系:A->B->C->X(1.0)A->D->X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版本的X,所以根据第一原则,A->D->X(2.0)路径短,所以X(2.0)会被解析使用
  2. 第一声明者优先 如果路径都一样长的话,第一原则就不行了,比如 A->B->Y(1.0)A->C->Y(2.0),Y(1.0)Y(2.0)的路径一样,所以这时候根据第二原则,先声明的被解析。A间接依赖Y(1.0)

所以maven依赖原则总结起来就两条:路径最短,申明顺序其次。

2.5 排除依赖

可以使用exclusions标签将传递过来的依赖排除出去。

<exclusions>
    <exclusion>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </exclusion>
</exclusions>

排除所有间接依赖:

<exclusions>
    <exclusion>
        <groupId>*</groupId>
        <artifactId>*</artifactId>
    </exclusion>
</exclusions>

2.6 版本锁定

采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,以锁定的版本为准添加到工程中,此方法在企业开发中经常使用。

版本锁定的使用方式:

第一步:在dependencyManagement标签中锁定依赖的版本

<dependencyManagement>
        <dependencies>
            <!-- SpringBoot的依赖配置-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.5.15</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
    </dependencies>
</dependencyManagement>

第二步:在dependencies标签中声明需要导入的maven坐标

<!-- Mysql驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

3.插件

Maven 本质上是一个插件框架,它的核心并不执行任何具体的构建任务, 所有 这些任务都交给插件来完成,例如编译源代码是由 maven- compiler-plugin 完成的。进 一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如 mavencompiler-plugin 的 compile 目标用来编译位于 src/main/java/目录下的主源码,testCompile 目标用来编译位于 src/test/java/目录下的测试源码。

以下常用插件:

  • maven-compiler-plugin:编绎阶段指定jdk版本。
  • maven-surefire-plugin:用于测试阶段的插件
  • maven-failsafe-plugin:用作集成测试的配置。
  • maven-checkstyle-plugin:可以帮助开发检测代码中不合规范的地方。
  • build-helper-maven-plugin:支持多个source/test/resource。
  • spring-boot-maven-plugin:可以帮助项目打包成一个fat jar。
  • jacoco-maven-plugin:生成单元测试覆盖率报告。
  • sonar-maven-plugin:使用该插件执行sonar扫描。

3.1. maven-compiler-plugin

这个插件会自动绑定到以下生命周期:

  • compile: compile main source files
  • testCompile: compile test source files

既然我们不主动声明,在使用命令mvn compile也会执行该插件,那么,在什么样的情况下,需要我们显式的声明该插件呢?

3.1.1 在编绎阶段指定JDK version

比如我们需要在编绎阶段使用不同的jdk的时候,可以显示的声明该插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                 <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    </plugins>
</build>

当然,我们也可以不用显示声明插件,而是使用properties来重置上述的source以及target中的值(这种方式更为常见):

<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

注:jdk9以上,不能用1.9,而是要使用9,11,17这样的格式。

1.2 使用MapStruct的时候,在插件中配置

MapStruct是Java的对象转换工具,可以通过依赖引入:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.2.Final</version>
</dependency><dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.2.Final</version>
</dependency>

但这样的依赖有个缺陷,就是无法和Lombok一起工作,如果POJO类被Lombok@Data修饰,而不是使用Getter/Setter,那么MapStruct在自动生成converter类的时候,会有问题。

如何解决? 可以在maven-compiler-plugin插件中配置annotationProcessorPaths。通过这样的方式,就可以解决MapStructLombok无法一起使用的问题。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.mapstruct</groupId>
                        <artifactId>mapstruct-processor</artifactId>
                        <version>1.5.2.Final</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.22</version>
                    </path>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok-mapstruct-binding</artifactId>
                        <version>0.2.0</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

1.3 在插件中配置Hibernate jpamodelgen

在编绎阶段生成JPA的 Metamodel,然后可以使用hibernate critieria queries

同样的,在maven-complier-plugin插件中配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.10.1</version>
            <configuration>
                <annotationProcessorPaths>
                    <path>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                        <version>1.18.22</version>
                    </path>
                    <path>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-jpamodelgen</artifactId>
                        <version>5.4.3.Final</version>
                    </path>
                </annotationProcessorPaths>
            </configuration>
        </plugin>
    </plugins>
</build>

其它依赖:spring-boot-starter-data-jpa,如何使用?

@SpringBootTest
public class CourseRepositoryTest {
    @Autowired
    private EntityManager entityManager;
​
    @Test
    public void test() {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Course> cq = cb.createQuery(Course.class);
​
        Root<Course> root = cq.from(Course.class);
        cq.select(root).where(cb.equal(root.get(Course_.id), 1));
​
        TypedQuery<Course> query = entityManager.createQuery(cq);
        List<Course> results = query.getResultList();
        System.out.println(results);
    }
}

3.1.4 其它

另外,maven-complier-plugin还可以与spring-boot-configuration-processor结合使用。具体如何使用可以参考:www.jb51.net/article/223…

3.2. spring-boot-maven-plugin

官网:docs.spring.io/spring-boot…

如果是传统web项目,我们会把项目打成war后,放入tomcat中启动。但如果我们的项目是Spring Boot项目,使用的是embed tomcat,那么我们一般会打包会一个可执行的jar,即:fat jar,通过命令java jar xxx.jar来启动项目。

spring-boot-maven-plugin可以帮助项目打包成一个fat jar。

<build>
    <finalName>springboot-k8sdemo</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.1.1.RELEASE</version>
            <configuration>
                <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

3.3maven-resources-plugin

插件作用:负责将项目资源复制到输出目录。有两种不同类型的资源:1.主要资源(main resource);2.测试资源(test resource)

插件目标

  1. resources:resources 拷贝main resourcesmain output directory.它绑定了process-resource 生命周期阶段,当执行compiler:compile插件的时候就会执行该阶段.
  2. resources:testResources 拷贝test resourcestest output directory.它绑定了process-test-resource 生命周期阶段,当执行surefire:test插件的时候就会执行该阶段.
  3. resource:copy-resources,拷贝资源到输出目录,需要在plugin.configuration下指定outputDirectoryresources

使用

  1. 指定resources插件的编码方式

     <properties>
         <!--  编码方式      -->
         <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
     </properties>
     <!-- 插件配置 -->
     <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-resources-plugin</artifactId>
         <version>2.5</version>
         <configuration>
             <encoding>${project.build.sourceEncoding}</encoding>
         </configuration>
     </plugin>
    
  2. 指定main resourcestest resources

     <sourceDirectory>src/main/java</sourceDirectory>
     <resources>
         <resource>
             <directory>src/main/resources</directory>
             <includes>
                 <include>**/*.properties</include>
                 <include>**/*.xml</include>
                 <include>**/*.yml</include>
             </includes>
             <filtering>true</filtering>
         </resource>
         <!--将手工引入的jar包编译运行 -->
         <resource>
             <directory>lib</directory>
             <targetPath>BOOT-INF/lib/</targetPath>
             <includes>
                 <include>**/*.jar</include>
             </includes>
         </resource>
     </resources>
     <testSourceDirectory>src/test/java</testSourceDirectory>
     <testResources>
         <testResource>
             <directory>src/test/resources</directory>
             <filtering>true</filtering>
             <includes>
                 <include>**/**</include>
             </includes>
             <excludes>
                 <exclude>**/*.pdf</exclude>
             </excludes>
         </testResource>
     </testResources>
    
  3. 过滤 把配置文件中使用${*}@*@ 表示的变量进行替换

    在resource中指定filtering为true

     <!-- 定义一个变量 -->
     <properties>
         <mysql.host>localhost</mysql.host>
         <mysql.port>3306</mysql.port>
     </properties>
     <resource>
         <directory>src/main/resources</directory>
         <filtering>true</filtering>
     </resource>
    

    可以将所有的变量添加到一个properties文件中,并通过filters.filter标签指定properties文件。

    例如:devMysql.properties文件

     mysql.host = localhost
     mysql.port = 3306
    

    配置如下:

     <filters>
         <filter>mysql.properties</filter>
     </filters>
    
  1. 如果资源目录下存在二进制文件,可以使用<configuration>中使用<nonFilteredFileExtensions>根据后缀来过滤。

     <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-resources-plugin</artifactId>
         <version>2.5</version>
         <configuration>
             <nonFilteredFileExtensions>pdf</nonFilteredFileExtensions>
             <encoding>${project.build.sourceEncoding}</encoding>
         </configuration>
     </plugin>
    
  2. 如果资源中的${*}字符不需要转义,需要在$ 前加 ``,并且在<configuration>里面使用<escapeString>.

     <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-resources-plugin</artifactId>
         <version>2.5</version>
         <configuration>
             <escapeString></escapeString>
             <encoding>${project.build.sourceEncoding}</encoding>
         </configuration>
     </plugin>
    

通用配置:

 <resources>
     <resource>
         <directory>src/main/resources</directory>
         <includes>
             <include>**/*.properties</include>
             <include>**/*.xml</include>
             <include>**/*.yml</include>
         </includes>
         <filtering>true</filtering>
     </resource>
 </resources>
 <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-resources-plugin</artifactId>
     <configuration>
         <delimiters>
             <delimiter>@</delimiter>
         </delimiters>
         <useDefaultDelimiters>false</useDefaultDelimiters>
     </configuration>
     <version>3.1.0</version>
 </plugin>

4.仓库

4.1远程仓库的配置

在平时的开发中,我们往往不会使用默认的中央仓库,默认的中央仓库访问的速度比较慢,访问的人或许很多,有时候也无法满足我们项目的需求,可能项目需要的某些构件中央仓库中是没有的,而在其他远程仓库中有,如JBoss Maven仓库。这时,可以在pom.xml中配置该仓库,代码如下:

<!-- 配置远程仓库 -->
<repositories>
    <repository>
        <id>jboss</id>
        <name>JBoss Repository</name>
        <url>http://repository.jboss.com/maven2/</url>
        <releases>
            <enabled>true</enabled>
            <updatePolicy>daily</updatePolicy>
        </releases>
        <snapshots>
            <enabled>false</enabled>
            <checksumPolicy>warn</checksumPolicy>
        </snapshots>
        <layout>default</layout>
    </repository>
</repositories>
  • repository: 在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库。
  • id: 仓库声明的唯一id,尤其需要注意的是,Maven自带的中央仓库使用的id为central,如果其他仓库声明也使用该id,就会覆盖中央仓库的配置。
  • name: 仓库的名称,让我们直观方便的知道仓库是哪个,暂时没发现其他太大的含义。
  • url: 指向了仓库的地址,一般来说,该地址都基于http协议,Maven用户都可以在浏览器中打开仓库地址浏览构件。
  • releases和snapshots: 用来控制Maven对于发布版构件和快照版构件的下载权限。需要注意的是enabled子元素,该例中releases的enabled值为true,表示开启JBoss仓库的发布版本下载支持,而snapshots的enabled值为false,表示关闭JBoss仓库的快照版本的下载支持。根据该配置,Maven只会从JBoss仓库下载发布版的构件,而不会下载快照版的构件。
  • layout: 元素值default表示仓库的布局是Maven2及Maven3的默认布局,而不是Maven1的布局。基本不会用到Maven1的布局。
  • 其他:对于releases和snapshots来说,除了enabled,它们还包含另外两个子元素updatePolicy和checksumPolicy。 1:元素updatePolicy用来配置Maven从远处仓库检查更新的频率,默认值是daily,表示Maven每天检查一次。其他可用的值包括:never-从不检查更新;always-每次构建都检查更新;interval:X-每隔X分钟检查一次更新(X为任意整数)。 2:元素checksumPolicy用来配置Maven检查校验和文件的策略。当构建被部署到Maven仓库中时,会同时部署对应的检验和文件。在下载构件的时候,Maven会验证校验和文件,如果校验和验证失败,当checksumPolicy的值为默认的warn时,Maven会在执行构建时输出警告信息,其他可用的值包括:fail-Maven遇到校验和错误就让构建失败;ignore-使Maven完全忽略校验和错误。

使用举例:

<repositories>
    <repository>
        <id>public</id>
        <name>aliyun nexus</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <releases>
            <enabled>true</enabled>
        </releases>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>public</id>
        <name>aliyun nexus</name>
        <url>https://maven.aliyun.com/repository/public</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </pluginRepository>
</pluginRepositories>

4.2远程仓库的认证

大部分的远程仓库不需要认证,但是如果是自己内部使用,为了安全起见,还是要配置认证信息的。 配置认证信息和配置远程仓库不同,远程仓库可以直接在pom.xml中配置,但是认证信息必须配置在settings.xml文件中。这是因为pom往往是被提交到代码仓库中供所有成员访问的,而settings.xml一般只存在于本机。因此,在settings.xml中配置认证信息更为安全。

<settings>
         ...
      <!--配置远程仓库认证信息-->
      <servers>
          <server>
              <id>releases</id>
              <username>admin</username>
              <password>admin123</password>
          </server>
     </servers>
 </settings>

这里除了配置账号密码之外,值关键的就是id了,这个id要跟你在pom.xml里面配置的远程仓库repository的id一致,正是这个id将认证信息与仓库配置联系在了一起。

4.3部署构件至远程仓库

我们自己搭建远程仓库的目的就是为了可以方便部署我们自己项目的构件以及一些无法从外部仓库直接获取的构件。这样才能在开发时,供其他对团队成员使用。 Maven除了能对项目进行编译、测试、打包之外,还能将项目生成的构件部署到远程仓库中。首先,需要编辑项目的pom.xml文件。配置distributionManagement元素,代码如下:

<distributionManagement>
        <repository>
            <id>releases</id>
            <name>public</name>
            <url>http://59.50.95.66:8081/nexus/content/repositories/releases</url>
        </repository>
        <snapshotRepository>
            <id>snapshots</id>
            <name>Snapshots</name>
            <url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url>
        </snapshotRepository>
</distributionManagement>

看代码,从命名上就看的出来区别,repository表示表示发布版本(稳定版本)构件的仓库,snapshotRepository表示快照版本(开发测试版本)的仓库。这两个元素都需要配置id、name和url,id为远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址。

配置好了就运行命令mvn clean deploy,Maven就会将项目构建输出的构件部署到配置对应的远程仓库,如果项目当前的版本是快照版本,则部署到快照版本的仓库地址,否则就部署到发布版本的仓库地址。 当前项目是快照还是发布版本是通过 true 这个来区分的。忘记的同学在看看上面的## 远程仓库的配置。

4.4镜像

如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。用过Maven的都知道,国外的中央仓库用起来太慢了,所以选择一个国内的镜像就很有必要,我推荐国内的阿里云镜像。 阿里云镜像:配置很简单,修改conf文件夹下的settings.xml文件,添加如下镜像配置:

<mirrors>
    <mirror>
        <id>huaweicloud</id>
        <name>mirror from maven huaweicloud</name>
        <mirrorOf>central</mirrorOf>
        <url>https://repo.huaweicloud.com/repository/maven/</url>
    </mirror>
    <mirror>
        <id>alimaven</id>
        <mirrorOf>central</mirrorOf>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    </mirror>
</mirrors>

上例子中,的值为central,表示该配置为中央库的镜像,任何对于中央仓库的请求都会转至该镜像,用户也可以用同样的方法配置其他仓库的镜像

这里介绍下<mirrorOf>配置的各种选项

  • <mirrorOf>*<mirrorOf>:匹配所有远程仓库。
  • <mirrorOf>external:*<mirrorOf>:匹配所有远程仓库,使用localhost的除外,使用file://协议的除外。也就是说,匹配所有不在本机上的远程仓库。
  • <mirrorOf>repo1,repo2<mirrorOf>:匹配仓库repo1h和repo2,使用逗号分隔多个远程仓库。
  • <mirrorOf>*,!repo1<mirrorOf>:匹配所有远程仓库,repo1除外,使用感叹号将仓库从匹配中排除。

需要注意的是,由于镜像仓库完全屏蔽了被镜像仓库,当镜像仓库不稳定或者停止服务的时候,Maven仍将无法访问被镜像仓库,因而将无法下载构件。

4.5仓库服务搜索

这里介绍2个提供仓库服务搜索的地址:

5. maven私服

5.1 私服说明

maven仓库分为本地仓库和远程仓库,而远程仓库又分为maven中央仓库、其他远程仓库和私服(私有服务器)。其中,中央仓库是由maven官方提供的,而私服就需要我们自己搭建了。

maven私服就是公司局域网内的maven远程仓库,每个员工的电脑上安装maven软件并且连接maven私服,程序员可以将自己开发的项目打成jar并发布到私服,其它项目组成员就可以从私服下载所依赖的jar。私服还充当一个代理服务器的角色,当私服上没有jar包时会从maven中央仓库自动下载。

nexus 是一个maven仓库管理器(其实就是一个软件),nexus可以充当maven私服,同时nexus还提供强大的仓库管理、构件搜索等功能。

5.2 搭建maven私服

①下载nexus

help.sonatype.com/repomanager…

②安装nexus

将下载的压缩包进行解压,进入bin目录

1559551510928转存失败,建议直接上传图片文件

打开cmd窗口并进入上面bin目录下,执行nexus.bat install命令安装服务(注意需要以管理员身份运行cmd命令)

1559551531544转存失败,建议直接上传图片文件

③启动nexus

经过前面命令已经完成nexus的安装,可以通过如下两种方式启动nexus服务:

在Windows系统服务中启动nexus

1559551564441转存失败,建议直接上传图片文件

在命令行执行nexus.bat start命令启动nexus

1559551591730转存失败,建议直接上传图片文件

④访问nexus

启动nexus服务后,访问http://localhost:8081/nexus

点击右上角LogIn按钮,进行登录。使用默认用户名admin和密码admin123登录系统

登录成功后点击左侧菜单Repositories可以看到nexus内置的仓库列表(如下图)

1559551620133转存失败,建议直接上传图片文件

nexus仓库类型

通过前面的仓库列表可以看到,nexus默认内置了很多仓库,这些仓库可以划分为4种类型,每种类型的仓库用于存放特定的jar包,具体说明如下:

①hosted,宿主仓库,部署自己的jar到这个类型的仓库,包括Releases和Snapshots两部分,Releases为公司内部发布版本仓库、 Snapshots为公司内部测试版本仓库

②proxy,代理仓库,用于代理远程的公共仓库,如maven中央仓库,用户连接私服,私服自动去中央仓库下载jar包或者插件

③group,仓库组,用来合并多个hosted/proxy仓库,通常我们配置自己的maven连接仓库组

④virtual(虚拟):兼容Maven1版本的jar或者插件

1559551723693转存失败,建议直接上传图片文件

nexus仓库类型与安装目录对应关系

1559551752012转存失败,建议直接上传图片文件

5.3 将项目发布到maven私服

maven私服是搭建在公司局域网内的maven仓库,公司内的所有开发团队都可以使用。例如技术研发团队开发了一个基础组件,就可以将这个基础组件打成jar包发布到私服,其他团队成员就可以从私服下载这个jar包到本地仓库并在项目中使用。

将项目发布到maven私服操作步骤如下:

  1. 配置maven的settings.xml文件
<server>
<id>releases</id>
<username>admin</username>   
<password>admin123</password>
</server>
<server>
<id>snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>

注意:一定要在idea工具中引入的maven的settings.xml文件中配置

  1. 配置项目的pom.xml文件
<distributionManagement>
<repository>
   <id>releases</id>
   <url>http://localhost:8081/nexus/content/repositories/releases/</url>
</repository>
<snapshotRepository>
   <id>snapshots</id>               <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>    </snapshotRepository>
</distributionManagement>

3. 执行mvn deploy命令

1559551977984转存失败,建议直接上传图片文件

5.4 从私服下载jar到本地仓库

前面我们已经完成了将本地项目打成jar包发布到maven私服,下面我们就需要从maven私服下载jar包到本地仓库。

具体操作步骤如下:

在maven的settings.xml文件中配置下载模板

<profile>
    <id>dev</id>
        <repositories>
        <repository>
            <id>nexus</id>
        <!--仓库地址,即nexus仓库组的地址-->
            <url>
            http://localhost:8081/nexus/content/groups/public/</url>
        <!--是否下载releases构件-->
            <releases>
            <enabled>true</enabled>
            </releases>
        <!--是否下载snapshots构件-->
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        </repositories>
<pluginRepositories>
    <!-- 插件仓库,maven的运行依赖插件,也需要从私服下载插件 -->
    <pluginRepository>
        <id>public</id>
        <name>Public Repositories</name>
        <url>
        http://localhost:8081/nexus/content/groups/public/</url>
        </pluginRepository>
        </pluginRepositories>
</profile>

在maven的settings.xml文件中配置激活下载模板

<activeProfiles>
    <activeProfile>dev</activeProfile>
</activeProfiles>

5.5. 将第三方jar安装到本地仓库和maven私服

在maven工程的pom.xml文件中配置某个jar包的坐标后,如果本地的maven仓库不存在这个jar包,maven工具会自动到配置的maven私服下载,如果私服中也不存在,maven私服就会从maven中央仓库进行下载。

但是并不是所有的jar包都可以从中央仓库下载到,比如常用的Oracle数据库驱动的jar包在中央仓库就不存在。此时需要到Oracle的官网下载驱动jar包,然后将此jar包通过maven命令安装到我们本地的maven仓库或者maven私服中,这样在maven项目中就可以使用maven坐标引用到此jar包了。

5.5.1 将第三方jar安装到本地仓库

①下载Oracle的jar包(略)

②mvn install命令进行安装

mvn install:install-file -Dfile=ojdbc14-10.2.0.4.0.jar -DgroupId=com.oracle -DartifactId=ojdbc14 –

Dversion=10.2.0.4.0 -Dpackaging=jar

③查看本地maven仓库,确认安装是否成功

1559552325997转存失败,建议直接上传图片文件

5.5.2 将第三方jar安装到maven私服

①下载Oracle的jar包(略)

②在maven的settings.xml配置文件中配置第三方仓库的server信息

<server>
  <id>thirdparty</id>
  <username>admin</username>
  <password>admin123</password>
</server>

③执行mvn deploy命令进行安装

mvn deploy:deploy-file -Dfile=ojdbc14-10.2.0.4.0.jar -DgroupId=com.oracle -DartifactId=ojdbc14 –

Dversion=10.2.0.4.0 -Dpackaging=jar –

Durl=http://localhost:8081/nexus/content/repositories/thirdparty/ -DrepositoryId=thirdparty

8. maven生命周期

Maven强大的一个重要的原因,是它有一个十分完善的生命周期模型(Lifecycle)。

Maven的生命周期模型可以从两个方面来理解

1.运行Maven的每个步骤都是由生命周期来定义的,这种预定义的默认行为将Maven的使用变得简单。可以拿前辈Ant作为对比,因为Ant中的每个步骤都需要手工去定义,使用起来就会复杂很多。

2.生命周期模型是一种标准。在不同的项目中,使用Maven的接口是一样的,这样就不用去仔细地理解每个项目的构建了。因为一般情况下,mvn clean、mvn install这样的命令是通用的。这一点也贯彻了【约定优于配置】的理念。

8.1 Maven有【三套】【相互独立】的生命周期

Maven有三套独立的生命周期,不了解的话很容易将Maven的生命周期看作一个整体。

1.清理生命周期(Clean Lifecycle):在开始真正的项目构建之前进行一些清理工作。

2.默认生命周期(Default Lifecycle):构建项目的核心部分,包括编译、测试、打包、部署等。

3.站点生命周期(Site Lifecycle):生成项目报告、站点,发布站点。

相互独立的意思就是说,你可以仅仅调用clean来清理工作目录,可以仅仅调用site来生成站点,这三个生命周期之间相互独立,并不存在强依赖关系。

当然了,也可以将三个生命周期组合使用,直接运行mvn clean install site来一起运行这三套生命周期。

8.2清理生命周期(Clean Lifecycle)

每套生命周期都由一组阶段(Phase)来组成,我们平时在控制台输入的命令总是会对应于一个特定的阶段,比如运行mvn clean,这里的clean就是清理生命周期的一个阶段。

清理生命周期一共包含了三个阶段:

1.pre-clean(预清理):执行一些需要在clean阶段之前完成的工作。

2.clean(清理):移除所有上一次构建生成的文件。

3.post-clean(后清理):执行一些需要在clean结算之后立刻完成的工作。

mvn clean中的clean就是上面的clean。在一个生命周期中运行某个阶段的时候,它之前的所有阶段都会被运行,也就是说,mvn clean就相当于mvn pre-clean clean。如果我们运行mvn post-clean,那么pre-clean和clean都会被运行。这是Maven的一个很重要的规则/特性,可以大大地简化命令的输入。

8.3默认生命周期(Default Lifecycle)

默认生命周期是Maven最重要的一个生命周期,绝大部分工作都发生在这个生命周期中。

默认生命周期包含了以下的阶段(这里只列出常用和必要了解的,实际上还有很多):

process-resources:复制并处理资源文件,至目标目录,准备打包。由插件maven-resources-plugin:resources负责

compile:编译项目的源代码。由插件maven-compiler-plugin:compile负责

process-test-resources:复制并处理资源文件,至目标测试目录。由插件maven-resources-plugin:testResources负责

test-compile:编译测试源代码。由插件maven-compiler-plugin:testCompile负责

test:使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署。由插件maven-surefire-plugin:test负责

package:接受编译好的代码,打包成可发布的格式,如 JAR 。

install:将包安装至本地仓库,以让其它项目依赖。

deploy:将最终的包复制到远程的仓库,以让其它开发人员与项目共享。

其实默认生命周期中还提供了很多的阶段,但是因为实际上会经常使用到的也就只有complie、test、package、install和deploy五个阶段,这里也就不全部列出来了。想要了解所有的阶段的话,可以到Maven的官方网站中查阅:maven.apache.org/guides/intr…

基本上,根据名称我们就能猜出每个阶段的用途。

8.4站点生命周期(Site Lifecycle)

站点生命周期存在以下四个阶段:

1.pre-site(预站点):执行一些需要在生成站点文档之前的工作。

2.site(站点):生成项目的站点文档。

3.post-site(后站点):执行一些需要在生成站点文档之后完成的工作,并且为部署做准备。

4.site-deploy(站点部署):将生成的站点文档部署到特定的服务器上。

在这些阶段中,最常用到的是site阶段和site-deploy阶段,用以生成和发布Maven站点。这是Maven提供的一个相当强大的功能之一,深得管理者喜爱,因为文档和统计数据能够自动生成,并且很好看。

Maven生命周期的总结

Maven的生命周期的知识点比较简单,在使用上只要记住,在同一套生命周期中运行任何一个阶段的时候,它前面的所有阶段都会被执行就行了。这就是为什么当我们运行mvn install命令的时候,代码会被编译(compile)、测试(test)和打包(package)。

但是这一特性在不同一套的生命周期中并不适用,比如很容易会认为清理生命周期是在默认生命周期之前的必经阶段。也就是说,会被认为如果执行默认生命周期中的阶段的话,清理生命周期中的所有阶段都会被执行。而这是不对的,不同一套的生命周期之间是相互独立的,其中的阶段并不会相互影响。如果需要在打包之前先清理之前打包的内容,需要单独运行清理生命周期。当然了,一般也会建议这么做,否则可能出现一些打包的奇怪问题,比如有一些文件并没有被更新的问题。

另外需要注意的是,这些对项目及进行编译、测试、打包、运行、部署等工作在Maven中都是抽象的定义,Maven自身是不会实际负责这些工作的,而是交由插件来实现。意思就是说,Maven命令的实际工作执行者是各种各样的插件,通过插件提供的命令与Maven提供的阶段相互绑定来完成相应的工作。因此Maven的插件机制是完全依赖于Maven的生命周期的,要想运用好这些Maven命令插件,理解Maven的生命周期也就变得十分重要。

img转存失败,建议直接上传图片文件

上面这张图是Idea开发工具中的Maven插件,只要理解了Maven的生命周期和其中的阶段,就能很好地使用这个插件了。

9. maven常用命令

  • clean: 清理(会默认把target文件夹中的数据清理)
  • compile: 编译,将Java 源程序编译成 class 字节码文件。
  • test: 测试 并生成测试报告
  • package:打包,动态 web工程打 war包,Java工程打 jar 包。
  • install: 将项目生成 jar 包放在仓库中,以便别的模块调用
  • mvn clean compile:表示先运行清理之后运行编译,会将代码编译到target文件夹中。
  • mvn clean compile -Dskip=true:跳过测试
  • mvn clean test:运行清理和测试。
  • mvn clean package:运行清理和打包。
  • mvn clean deploy:运行清理和发布(发布到私服上面)。
  • mvn dependency:list : 查看当前项目已解析的依赖。
  • mvn dependency:tree 查看当前项目的依赖树。
  • mvn dependency:analyze 分析当前依赖包信息。需要关注Used undeclared dependencies,指的是项目中已使用但未声明的依赖。Unused declared dependencies,指的是项目中未使用但已声明的依赖。可以从这两个点去查看当前依赖包情况。