# maven 中 geo tools 的引入 - maven 的 repository 与 mirror

# maven 中 geo tools 的引入 - maven 的 repository 与 mirror

# 一,问题描述

起因是这样的,我想要引入 GeoTools 包,却发现即使按照官方 quick start 来操作,也没有引入成功,始终是找不到 jar 包,百思不得其解。

按照官网和谷歌百度搜索的结果看
要使用 GeoTools,首先引入需要的 GeoTools 的模块。GeoTools 有很多模块,如 shapefile,csv 等。
这个是我要引入的 geojson 模块

<dependency>
   <groupId>org.geotools</groupId>
   <artifactId>gt-geojson</artifactId>
   <version>19.0</version>
</dependency>

然后添加 geo tools 官方的仓库

<repository>
   <id>osgeo</id>
   <name>OSGeo Release Repository</name>
   <url>https://repo.osgeo.org/repository/release/</url>
   <snapshots><enabled>false</enabled></snapshots>
   <releases><enabled>true</enabled></releases>
</repository>
<repository>
   <id>osgeo-snapshot</id>
   <name>OSGeo Snapshot Repository</name>
   <url>https://repo.osgeo.org/repository/snapshot/</url>
   <snapshots><enabled>true</enabled></snapshots>
   <releases><enabled>false</enabled></releases>
</repository>

但就是找不到 jar 包

image-20240809142140245

dependencies 也是报错

image-20240809142410052

后来尝试将仓库以镜像的方式写入到 settings.xml 之中,结果发现可行了。(当然后续发现这种方法是错误的解决方案,正确的做法在后面)

# 二,原理说明

出错原因: 没有理解清楚 maven 的 repository 与 mirror 的关系,错误地将阿里云镜像的 mirrorOf 参数值设置为 *(星号,通配符,表示匹配全部仓库)(正确的参数值为 central)

为了让各位更好地理解这个问题,有必要占用一些篇幅介绍一下 maven 的基本信息和相关概念

# 2.1 maven 的主要功能

以下描述摘自维基百科

Maven 是一个主要用于 Java 项目的构建自动化工具。Maven 还可以用来构建和管理使用 c#、Ruby、Scala 和其他语言编写的项目。Maven 项目由 Apache 软件基金会托管,它以前是 Jakarta 项目的一部分。

Maven 解决了构建软件的两个方面:如何构建软件及其依赖关系。

maven 的主要功能有两个:一个是解决项目的构建:包括编译(build)测试(test)、** 打包(package)部署(deploy)** 等,maven 使用生命周期的概念描述这一过程,并通过插件实现和控制项目构建各个阶段的执行。

下图为完整的 maven 生命周期

image-20240809143214955

maven 的另一个功能就是解决项目之间的依赖关系并从仓库 (repository) 自动下载需要的 jar 包。maven 使用项目对象模型 (Project Object Model,POM) 实现对项目的抽象和管理。

项目对象模型 (POM) 提供了单个项目的所有配置。一般配置包括项目的名称(name)、所有者(owner)及其对其他项目的依赖关系(dependencies)。还可以配置构建过程的各个阶段,这些阶段以插件(plugins)的形式实现。

默认情况下,所有的 POM 都继承自超级 POM。超级 POM 提供默认配置,比如默认源目录、默认插件等等。

maven 将约定大于配置作为其设计理念,约定一一些默认的配置,如项目的默认结构,对某个项目坐标,依赖和插件的规定的配置方法 (IDE 通常会帮助检查配置项的正确性) 等。

下图表示默认的 maven 项目 目录

image-20240809143516603

# 2.2 仓库

所有的 maven 项目都存储在服务器上,改服务器被抽象为仓库 (repository),当用户需要某些 jar 包时就可以从仓库中下载。

maven 通过超级 POM 机制配置了默认的仓库。由于所有的 POM 都隐式地继承自超级 POM,超级仓库中配置了中央仓库,因此所有的项目默认配置了中央仓库。

对于 Maven3,超级 POM 在文件 % MAVEN_HOME%/lib/maven-model-builder-x.x.x.jar 中的
org/apache/maven/model/pom-4.0.0.xml 路径下、

对于 Maven2,超级 POM 在文件 % MAVEN_HOME%/lib/maven-x.x.x-uber.jar 中的
org/apache/maven/project/pom-4.0.0.xml 目录下。

默认配置的部分内容如下:

<repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>

我们可以自己添加仓库,如我添加了提供 GeoTools 相关包的仓库,id 为 osgeo ,url 地址为 https://repo.osgeo.org/repository/release/

在项目的 pom.xml 中加入仓库配置:

<repository>
   <id>osgeo</id>
   <name>OSGeo Release Repository</name>
   <url>https://repo.osgeo.org/repository/release/</url>
   <snapshots><enabled>false</enabled></snapshots>
   <releases><enabled>true</enabled></releases>
</repository>

# 2.3 镜像

由于 maven 的中央仓库在国外,国内访问速度较慢,一般我们采用配置镜像(mirror)的方式从国内的镜像服务器中下载资源。

maven 根据 setting.xml 文件中配置的镜像拦截发往原仓库的请求,并将其转发到镜像仓库。

即:当一个镜像的 mirrodOf 参数与某个仓库的 id 参数相匹配,就向该镜像请求资源,否则向原仓库请求资源。

阿里云镜像是常用的 maven 镜像之一,其镜像了中央仓库的所有资源。

setting.xml 文件中阿里云镜像的配置如下:

<!-- 阿里云镜像 -->
<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

setting.xml 文件中,我们设置阿里云镜像的 mirrorOf 属性为 central ,以此去匹配 id 属性为 central 的中央仓库。这样所有对中央仓库发起的请求,都会被转发给阿里云镜像,大大提高了资源的下载速度。

# 2.4 仓库与镜像的关系

当我们配置了多个仓库和多个镜像时,maven 执行的策略为:

1,maven 根据镜像配置文件(setting.xml)自上至下地依次查看所有的镜像,对每一个仓库依次进行匹配,并使用第一个匹配上的镜像。被镜像匹配的仓库,仓库的 url 被替换为镜像的 url,没有匹配的仓库,url 不变。

2,查询各仓库是否包请求的资源(项目),如都没有,则报错(如未找到),否则从第一个匹配上的仓库拉取资源。
image-20240809143954175

# 三,解决方案与小技巧

1,不是所有的 jar 包都被包含在 maven 中央仓库中,如果中央仓库没有该资源,就需要配置第三方仓库(也可以理解为别人的公开私服)。maven 中央仓库不包含 GeoTools 的相关资源,因此需要单独配置 OSGeo Release Repository 仓库。

2,阿里镜像和清华镜像只提供对中央仓库的资源镜像,其 mirrorOf 属性的值只能设置为 central,不要设置为 * 。如果设置为 *,则所有仓库的 url 都会被替换,对于本文的情况,就是本来应当发往 OSGeo Release Repository 仓库的请求被发往阿里云镜像,而阿里云镜像不包含 GeoTools 的资源,自然是找不到了。正确的做法是每个镜像的 mirrorOf 属性应与该镜像对应的仓库的 id 属性保持一致。

3,还有一种骚操作(错误操作),就是在 setting.xml 将仓库作为镜像配置进去。由于 maven 的镜像机制,仓库的 url 会被替换为第一个匹配上的镜像,那么在阿里云镜像之前添加一个(伪)仓库镜像,也可以解决问题。但是这个方法肯定是错误用法(但是很骚)。

# 错误配置

setting.xml

<!-- 阿里云镜像 -->
<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>*</mirrorOf> <!-- 正确的属性为 central -->
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

或者

<!-- osgeo(伪)镜像 -->
<mirror>
    <id>mirror-osgeo</id>
    <mirrorOf>osgeo</mirrorOf>
    <name>Mirror Osgeo</name>
    <url>https://repo.osgeo.org/repository/release/</url>
</mirror>
<!-- 阿里云镜像 -->
<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>*</mirrorOf> <!-- 正确的属性为 central -->
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

pom.xml

<repository>
   <id>osgeo</id>
   <name>OSGeo Release Repository</name>
   <url>https://repo.osgeo.org/repository/release/</url>
   <snapshots><enabled>false</enabled></snapshots>
   <releases><enabled>true</enabled></releases>
</repository>

# 正确配置

setting.xml

<!-- 阿里云镜像 -->
<mirror>
    <id>nexus-aliyun</id>
    <mirrorOf>central</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

pom.xml

<repository>
   <id>osgeo</id>
   <name>OSGeo Release Repository</name>
   <url>https://repo.osgeo.org/repository/release/</url>
   <snapshots><enabled>false</enabled></snapshots>
   <releases><enabled>true</enabled></releases>
</repository>

# 四,如何知道是否需要配置仓库?

在 maven 的官网可以查询相关项目的信息,项目页面的标签栏标识了存储了该项目的仓库,只要是存储在中央仓库的项目都会标识 Central 标签,此时就不用配置新的仓库。

image-20240809144253604

如果标签栏中没有标识 Central 仓库,说明中央仓库不包含该项目,需要配置新的仓库。
如对于 GeoTools 包,从图中我们可知,由于 Central 仓库不包含该包,我们就需要从其标签栏标识的 GeoSolutions 仓库、Geomajas 仓库、Boundless 仓库或 OSGeo 仓库拉取 GeoTools 包的资源
image-20240809144310027