关于maven:Maven进阶学习指南-京东云技术团队

4次阅读

共计 16764 个字符,预计需要花费 42 分钟才能阅读完成。

前言

当咱们在开发我的项目时,有时须要用到内部依赖组件,例如当咱们须要 Json 序列化的时候须要用到 FastJson 组件,咱们能够通过下载对应 jar 包加载到我的项目中。但当一个大的我的项目同时须要依赖各种各样的内部服务,就存在着配置繁琐、依赖抵触等问题,因而能够通过 maven 来实现对应的依赖治理性能。

一、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 仓库【重要】

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

其对应关系为:

(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

配置了 mirror

二、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-INF web 利用文件目录,web 我的项目的信息,比方寄存 web.xml、本地图片、jsp 视图页面
${basedir}/target 打包输入目录
${project.version} 我的项目版本
${project.groupId} 我的项目 groupid

2.1.5 resources

resources标签用来标识我的项目在编译运行时须要额定编译的文件。例如手工引入 jar 包、不同运行环境对应不同的 profile。

<build>
     <resources>
         <!-- 首先将默认 resources 目录下的所有文件包含 -->
         <resource>
             <directory>src/main/resources</directory>
             <filtering>true</filtering>
             <!-- 只编译所有以.fxml 结尾的文件 -->
             <includes>
                 <include>**/*.fxml</include>
             </includes>
             <!-- 排除掉所有的 yaml 文件 -->
             <excludes>  
                    <exclude>**/*.yaml</exclude>  
             </excludes>
         </resource>
         <!-- 将不同环境下对应的不同 yaml 或 properties 文件编译运行 -->
         <resource>
             <!--
             <directory>src/main/profiles/dev</directory>
             <directory>src/main/profiles/beta<directory>
             <directory>src/main/profiles/pre</directory>
             -->
             <directory>src/main/profiles/product</directory>
             <filtering>true</filtering>
             <includes>
                 <include>**/*.fxml</include>
             </includes>
         </resource>
         <!-- 将手工引入的 jar 包编译运行 -->
         <resource>
                <directory>lib</directory>
                <targetPath>BOOT-INF/lib/</targetPath>
                <includes>
                    <include>**/*.jar</include>
                </includes>
            </resource>
     </resources>
</build>

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.6 modules

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

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

三、null:jrdp-common:null:jar 问题解决

3.1 包找不到问题

咱们某次在开发性能的时候,在咱们的我的项目中援用了伏羲另外一个零碎的 jar 包,然而预发环境下编译的时候却发现构建失败,起因是

因为过后我的项目有用到京东本人的仓库,所以咱们过后第一反馈是去仓库中查找,后果发现仓库中是有这个 jar 包的。

在发现并不是最常见的 jar 包不存在的问题后,咱们开始剖析报错起因,发现报错的 jrdp-common这个包并不是咱们间接援用的,而是在咱们援用的 jar 包中援用的,并且 null:jrdp-common:null:jar能够揣测后面应该是 groupID与 version

假如咱们的我的项目是 A 我的项目,援用的我的项目是 B 我的项目,也就是 A->B->jrdp-common

于是咱们关上 B 我的项目,查看 B 的 pom 构造。

发现 B 我的项目的 pom 中的确援用了 jrdp-common 这个包,然而并没有指定版本,是因为继承了 xx-parent这个包,咱们在这个包中的确也找到了指定的版本号,因而就排除了我的项目中没有指定 groupid 与版本号的问题。

这个时候如同就问题就陷入了思路,然而咱们留神到,咱们之前另一个私服上也是有这个包的,那么之前的在另一个私服上援用如同是没有问题的,咱们查看了私服了上的 pom 文件,发现也是跟我的项目一样的。

而后咱们就忽然想到,会不会是仓库中的包有问题,果不其然

没有指定 parent 也没有指定版本号,于是咱们批改了这个版本的 pom,至此问题解决。

总结:因为咱们的零碎曾经被好多个团队中转接手过,因而可能在某些中央踩了不少坑,像这种问题应该就是之前的团队上传了一些有问题的 jar 包,导致依赖不可用,然而因为咱们之前始终用的私服是没有什么问题的,只到这次用到了仓库问题才浮现。

另外,此问题并不具备普适性,然而当遇到了 groupid 不能未空的时候能够依照此办法进行排查。

作者:京东科技 韩国凯

内容起源:京东云开发者社区

正文完
 0