从0到0.1学习 maven(二:坐标、依赖和仓库)

news2025/1/10 23:59:07

该文章为maven系列学习的第二篇
第一篇快速入口:从0到0.1学习 maven(一:概述及简单入门)

第二节:坐标、依赖与仓库

    • 坐标
    • 依赖
      • 依赖范围
      • 传递性依赖
      • 依赖调解
      • 可选依赖
      • 依赖排除
      • 归类依赖
      • 优化依赖
    • 仓库
      • 路径生成
      • 仓库分类
        • 本地仓库
        • 远程仓库
      • 快照
      • 部署至远程仓库
      • 从仓库解析依赖的机制
      • 镜像
    • 第二节完

坐标

上一篇说到,作为项目依赖管理工具的maven,坐标是重要的基础。
maven的坐标系统包括 groupId, artifactId, version, packaging, classifier。每个构建都有并且必须有一个坐标,这也意味着开发自己项目的时候,也需要为其定义坐标。下面介绍每个坐标的意义:

  • groupId:定义当前maven项目隶属的实际项目
  • artifactId: 定义一个maven模块。一般的,maven生成的构建会用artifactId作为开头。此外,通常会将 项目的实际名称作为前缀。例如实际项目名为nexus,模块有core,service,web,那artifactid可定义为nexus-core,nexus-service, nexus-web.
  • version: 定义maven项目当前所处的版本。
  • packaging:定义maven的打包方式,默认为jar
  • classifier:用于帮助定义构架输出的一些附属构件。
    其中,前三个都是必须的,packaging是可选的,classifier不能直接定义。

依赖

首先,依赖声明可以包含如下元素

        <dependency>
            <groupId>...</groupId>
            <artifactId>...</artifactId>
            <version>...</version>
            <type>...</type>
            <scope>...</scope>
            <exclusions>
                <exclusion>
                    <groupId>...</groupId>
                    <artifactId>...</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

以下会介绍这些标签的使用。

依赖范围

首先,maven在编译项目主代码的时候需要使用一套classpath,编译和运行会使用另外两套classpath。这主要是由于在不同场景下的依赖不同,比如在测试场景下要使用JUnit,在编译和运行场景下却无需使用。classpath共有三种:编译classpath,测试classpath,运行classpath。
依赖范围就是用来控制与三种classpath之间的关系,共有以下六种依赖范围,默认为compile

  • compile:编译依赖范围。对三种classpath都有效
  • test: 测试依赖范围,只对测试classpath有效
  • provided:已提供依赖范围,对编译和测试classpath有效。
  • runtime:运行时以来范围,对测试和运行classpath有效
  • system:系统依赖范围,这种依赖的依赖范围与provided一致,但需要通过systemPath显式的指定依赖文件的路径。因此这种方法对本地是有强依赖性的,需要谨慎使用。
  • import:导入依赖范围。

传递性依赖

maven的依赖是可传递的,也就是,不需要再引入依赖的依赖。A对B有依赖,B依赖着C,maven会解析直接依赖的pom,将必要的间接依赖使用传递性依赖的形式引入到当前的项目中。这里A对于C就是传递性的依赖。
此外,传递范围也会对依赖性传递产生影响,依然使用上面的例子,A对于B是第一直接依赖,B对于C是第二直接依赖,依赖的传递范围与传递性影响如下表,左侧列表示第一依赖范围,上方行表示第二依赖范围。

compiletestprovidedruntime
compilecompile--runtime
testtest--test
providedprovided-providedprovided
runtimeruntime--runtime

依赖调解

传递性依赖可以帮助我们省略很多依赖声明,但是项目中可能面对的问题是,对于同一个包引入了不同的版本,哪个版本会被解析使用呢?Maven依赖调解的第一原则就是

路径近者优先

例如,项目中有两条依赖A→B→C(Version 1.0);A→C(Version 2.0)。根据路径近者优先的原则,会选择C(Version 2.0)。那针对相同路径长度的依赖,则采用第二原则

第一声明者优先

简单来讲,就是在路径长度一样的时候,谁先声明就使用谁。

可选依赖

若项目A中的依赖B,其拥有可选依赖C,则C不会被传递。需要在A中进行显式的依赖。举个例子,若B的作用是作为多种数据库的JDBC,它将mysql,oracle,等等都作为了可选依赖,但是在使用的时候只会用到一种依赖。那A在使用B时,就要显式地在A的pom中说明对mysql还是oracle等的依赖。

依赖排除

有时会由于某些原因,不希望自动导入某些传递性依赖。可以使用extensions进行显式的依赖排除。只需要groupId和artifactId就可以定位到该依赖包,而不用version,因为本身只会引入一个版本的依赖。
关于idea中如何筛选以及排除依赖,可以参考我之前写的一篇教程。
Java项目使用intellij-IDEA查看依赖包版本是否有冲突(方法及工具)附截图

归类依赖

用过spring的朋友们肯定知道,如果引入spring框架相关的包,会叽里呱啦引入很多,比如spring-beans, context, core, support,这些都是来自一个项目的不同模块,也需要用相同版本。另外在升级的时候,这些包也要一起升级,因此这可以使用变量的方式,来做归类。

<properties>
	<spring-version>4.1.1</spring-version>
</properties>
.......

<dependencies>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>${spring-version}</version>
	</dependency>
	......
</dependencies>

优化依赖

经过以上的种种操作,最后得到的依赖叫可解析依赖。可以用如下命令查看当前项目中的依赖。

mvn dependency:list

此外,也可以通过以下命令来查看maven解析的路径

mvn dependency:tree

还有个实用的小工具

mvn dependency:analyze

它可以帮助我们找到已引入但是没有使用的依赖,和没有引入但是使用了的依赖。但是对于引入却没使用的依赖不要盲目的进行删除。因为这里分析的只是编译主代码和测试代码用到的依赖,而运行和执行测试的代码依赖没有被包含。

仓库

简单来讲,仓库就是根据前面说的坐标存放构件的地方。插件,依赖,或者项目模块构建的输出都可以是构件。

路径生成

仓库是一层一层的,根据groupId,artifactId,version生成类似于文件系统的路径。举个例子,假设groupId=org.sth.someorg, artifactId=lalala,version=9.9.9,classifier=jdk8, packaging=jar

  1. 首先根据groupId,将.用/替换 即变为org/sth/someorg
  2. 再把artifactId加入刚刚的路径里org/sth/someorg/lalala
  3. 加入版本信息 org/sth/someorg/lalala/9.9.9
  4. 依次加入artifactId,连接符,与version:org/sth/someorg/lalala/9.9.9/lalala-9.9.9
  5. 如果有classifier也一起加入:org/sth/someorg/lalala/9.9.9/lalala-9.9.9-jdk8
  6. 最后加入拓展名:org/sth/someorg/lalala/9.9.9/lalala-9.9.9.jar

仓库分类

maven的仓库分成两类,本地仓库和远程仓库。会根据坐标现在本地仓库里找,如果本地仓库有该构件则直接使用。如果没有那就会去远程仓库找,找到后再放到本地仓库。如果本地和远程都没有找到,则报错。

本地仓库

默认情况下,用户在自己的用户目录下会有.m2/repository的仓库目录。可以通过编辑.m2目录下的settings.xml文件,设置localRepository元素值来定义想要的仓库地址。但是默认这个文件是不存在的,需要用户在$M2_HOME/conf/settings.xml复制过来。

另外,构建除了从远程仓库下来到本地,还可以将本地项目的构建安装到maven仓库中。我们使用的install就是在将构建结果放入本地仓库。

远程仓库

远程仓库可以分成,中央仓库,私服和其他公共库

  • 中央仓库是默认的远程仓库,也就是 https://repo.maven.apache.org/maven2

在这里插入图片描述

  • 私服是架设在局域网的仓库,在下载构建时,maven会先从私服请求,如果私服没有则从外部远程下载,缓存在私服后再为maven下载提供请求。

  • 可以在settings.xml中的repositories元素下增加repository标签来声明远程仓库。

快照

首先,先看一下带有快照版本号的版本号长什么样子

快照版:2.1-SNAPSHOT
时间戳版:2.1-20230131.170912-3

快照版实际上是未完成开发的非正式不稳定版本。在将版本号设定成x.x-SNAPSHOT,在发布到私服时,maven会为其自动打上时间戳,这样在之后就可以快速的找到当前的最新版本。以上面的时间戳版本号为例,2.1-20230131.170912-3代表着2.1版本下2023年1月31日17点09分12秒的第三个构件。如果项目中配置了snapshot的依赖,在项目构建时则会从仓库中检查最新的构件,有更新则下载。默认每天检查一次更新,可以通过仓库配置的updatePolicy设置更新频率,也可以使用-U参数强制更新mvn clean install -U

部署至远程仓库

上面提到了,快照需要发布到私服保证能获取最新版本,那怎么将构建发布至远程仓库呢?

  1. 编辑项目的pom.xml,配置distributionManagement。
    子标签repository表示发布版本的构建仓库,snapshotRepository表示快照版本的仓库。其中id,name,url都是必选的。id表示远程仓库的唯一标识,name方便人阅读,url表示该仓库的地址。
<project>    
  ...    
  <distributionManagement>    
    <repository>    
      <id>nexus-releases</id>    
      <name>Nexus Release Repository</name>    
      <url>http://127.0.0.1:8080/nexus/content/repositories/releases/</url>    
    </repository>    
    <snapshotRepository>    
      <id>nexus-snapshots</id>    
      <name>Nexus Snapshot Repository</name>    
      <url>http://127.0.0.1:8080/nexus/content/repositories/snapshots/</url>    
    </snapshotRepository>    
  </distributionManagement>    
  ...    
</project>    
  1. 认证
    在pom.xml中添加server标签配置仓库认证信息
<servers>
                
		<server>
			<id>nexus-releases</id>
			<username>ptyp</username>
			<password>yourpassword</password>
        </server>
</servers>

这里的server id要和前面repository的id保持一致。

  1. 运行mvn clean deploy。
    maven就会将构件部署到对应的远程仓库上。

从仓库解析依赖的机制

  1. 当依赖范围为system时,直接从本地解析构建
  2. 解析好路径后,如果在本地仓库发现构件则解析成功
  3. 若本地无该构建,若版本为x.x这种显式的结构,则从远程仓库下载并完成解析
  4. 若版本为RELEASE或LASTEST,则根据更新策略读取所有远程仓库的groupId/artifactid/maven-metadata.xml,将其与本地仓库的元数据合并后得到对应的版本,再重复步骤2和3
  5. 若版本为SNAPSHOT,则根据更新策略读取所有远程仓库的groupId/artifactid/version/maven-metadata.xml,将其与本地仓库的元数据合并后得到对应的版本,再重复步骤2和3
  6. 若解析后版本号为时间戳格式,则复制该构件并将其重命名例如SNAPSHOT,并使用新复制出来的构件。(简单来说,就是最后使用的构件名不会包含时间戳)

此外,有几点需要额外注意:

  • 如果使用非x.x这样显式的版本号,即以上的4和5,需要在settings.xml中的仓库配置中打开对应开关(<releases><enabled>)
	<profiles>
	
		<profile>
			<id>dev</id>
			<repositories>
				<repository>
					<id>mvn-repo</id>
					<url>xxx</url>
					<releases>
						<enabled>true</enabled>
					</releases>
					<snapshots>
						<enabled>true</enabled>
						<updatePolicy>always</updatePolicy>
					</snapshots>
				</repository>
			</repositories>
		</profile>
	</profiles>
  • updatePolicy配置了检查更新的频率如每日,从不,永远检查等。但若用户在命令行中使用了-U,maven则会忽略updatePolicy的配置。
  • RELEASE表示最新发布版本,LATEST表示的是最新版本(包含SNAPSHOT),这两个都是基于groupId/artifactid/maven-metadata.xml文件得到的
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.2.10.BUILD-SNAPSHOT</version>
  <versioning>
    <lastest>1.1.1-SNAPSHOT<lastest>
    <release>1.1.0<release>
    <versions>
		<version>0.8.0</version>
		<version>0.9.0</version>
		<version>1.1.0</version>
		<version>1.1.1-SNAPSHOT</version>
	</versions>
    <lastUpdated>20201023123408</lastUpdated>
  </versioning>
</metadata>

可以看到lastest指向了最新的版本,而versions里面列着全部的版本。
但是需要说明的是由于release和lastest这样的声明获取到的版本可能随时都会发生改变,因此可能会存在潜在的问题。从maven3开始已经不支持配置latest和release。但如果不配置插件版本,默认会为release。

  • SNAPSHOT表示的是快照版本,是基于groupId/artifactid/version/maven-metadata.xml文件得到的
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.2.10.BUILD-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20201023.122514</timestamp>
      <buildNumber>33</buildNumber>
    </snapshot>
    <lastUpdated>20201023123408</lastUpdated>
    <snapshotVersions>
      <snapshotVersion>
        <classifier>javadoc</classifier>
        <extension>jar</extension>
        <value>5.2.10.BUILD-20201023.122514-33</value>
        <updated>20201023122514</updated>
      </snapshotVersion>
      <snapshotVersion>
        <classifier>sources</classifier>
        <extension>jar</extension>
        <value>5.2.10.BUILD-20201023.122514-33</value>
        <updated>20201023122514</updated>
      </snapshotVersion>
      <snapshotVersion>
        <extension>jar</extension>
        <value>5.2.10.BUILD-20201023.122514-33</value>
        <updated>20201023122514</updated>
      </snapshotVersion>
    </snapshotVersions>
  </versioning>
</metadata>

这里比上一部分多了timestamp和buildNumber两个子元素,分别代表了时间戳和构建号,将这两个值拼起来则会得到仓库中该快照的实际版本号。

  • maven-metadata.xml 不一定永远都是正确的,如果出现构建解析错误可能是元数据出了问题,那就需要人工修复。

镜像

如果A的内容都能从B获取,则将B称为A的镜像。镜像一般都会比原仓库的获取速度更快,因此可以使用镜像来替代中央仓库。

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

mirrorOf指的是,所有对于central的请求都会转到该镜像。

另外,镜像也可以结合私服。因为私服可以代理包括中央仓库在内的任何外部仓库,因此使用私服地址就相当于使用了所有需要的外部仓库,简单讲就是私服是所有仓库的镜像,由此简化配置。

<mirror> 
	<id>some-internal-repo</id> 
	<name>Internal Repository Name</name> 
	<url>http://-----------</url> 
	<mirrorOf>*</mirrorOf> 
</mirror>

这里的mirrorOf是*表示,所有仓库的镜像都会被转到该url上。

mirrorOf中如果配置多个仓库可以使用逗号进行分割,也可以使用!进行排除,如<mirrorOf>,!repo/mirrorOf>代表匹配除了repo之外的全部远程仓库;
<mirrorOf>external:
</mirrorOf> : 表示匹配除了不在本机之外(文件系统或localhost)的远程仓库

镜像会完全拦截mirrorOf中配置的请求,因此就算镜像地址失效,也不会有请求打到被镜像的地址上。

第二节完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/189512.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Day 16 Enable注解

Springboot中提供了很多Enable开头的注解&#xff0c;这些注解是冬天开启某些功能的&#xff0c;而其底层使用Import注解导入一些配置类&#xff0c;实现Bean的动态加载1 EnableAutoConfigurationTarget(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inhe…

京东十年T8架构师手撕MySQL:手写666页核心知识,超85%问题全解

MySQL是开放源码的关系数据库管理系统&#xff0c;由于 性能高、成本低、可靠性好&#xff0c;成为现在最流行的开源数据库。 MySQL学习指南 笔记包含了3个大章节&#xff0c;13个小章节&#xff1a; 基础篇 MySQL数据类型MySQL运算符MySQL函数MySQL数据库查询语句 核心篇 …

​力扣解法汇总2319. 判断矩阵是否是一个 X 矩阵

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣 描述&#xff1a; 如果一个正方形矩阵满足下述 全部 条件&#xff0c;则称之为一个 X 矩阵 &#…

自动化设备ERP系统对企业管理有什么好处?

随着自动化设备制造企业的快速发展&#xff0c;规模和产能的不断扩大&#xff1b;设备也不断增加、品种越来越多&#xff1b;企业信息化建设也不断发展和完善, 自动化设备ERP系统已经成为企业信息化建设的一个有机组成部分。自动化设备管理已进入信息化、数字化时代。自动化设备…

机器学习之求解无约束最优化问题方法(手推公式版)

文章目录前言1. 基础知识1.1 方向导数1.2 梯度1.3 方向导数与梯度的关系1.4 泰勒展开公式1.5 Jacobian矩阵与Hessian矩阵1.6 正定矩阵2. 梯度下降法3. 牛顿法4. 拟牛顿法5. 代码实现结束语前言 本篇博文主要介绍了机器学习里面的常见的求解无约束最优化问题的方法&#xff0c;包…

LeetCode——1664. 生成平衡数组的方案数

一、题目 给你一个整数数组 nums。你需要选择恰好一个下标&#xff08;下标从0开始&#xff09;并删除对应的元素。请注意剩下元素的下标可能会因为删除操作而发生改变。 比方说&#xff0c;如果 nums [6,1,7,4,1] &#xff0c;那么&#xff1a; 选择删除下标 1 &#xff0…

在CentOS-6.9部署apache服务

文章目录一 系统环境二 部署服务2.1 yum安装软件2.2 修改主配置文件2.3 修改防火墙规则2.4 访问测试三 主配置文件参数3.1 主配置文件常规语句3.2 主配置文件日志控制语句3.3 主配置文件的性能控制语句一 系统环境 参数值主机IP10.0.0.100主机名test操作系统版本CentOS releas…

css 过渡动画

目录过渡动画1 css 属性1.1 transform 变换&#xff08;平移旋转缩放&#xff09;1.2 animation 动画1.2.1 keyframes1.3 transition 过渡1.4 比较2 方式2.1 css 伪类2.2 vue <Transition> 组件2.2.1 默认名称2.2.2 自定义名称2.2.3 自定义 class2.2.4 配合 animation2.2…

sqlserver存储过程简单游标示例

test数据库有表如下&#xff1b; 创建一个存储过程&#xff0c;输出姓名和电话&#xff1b; CREATE PROCEDURE printname AS BEGINDECLARE sName varchar(20), phone varchar(20)DECLARE cursor1 CURSOR FOR --定义游标SELECT name,phonenumber from t_student OPEN cursor1 …

OpenStack的“神秘组件” 裸金属(Ironic)管理使用

OpenStack是目前全球部署最广泛的开源云基础架构&#xff0c;在OpenStack中提供的裸金属服务的项目是Ironic。OpenStack的官网主要介绍裸金属的用途在如下5方面&#xff1a; &#xff08;1&#xff09;高性能计算&#xff1b; &#xff08;2&#xff09;无法虚拟化的硬件设备的…

DSVW通关教程

DSVW通关教程 首先整体浏览网站 Blind SQL Injection (boolean) 基于布尔型的盲注: HTTP请求的响应体中不会明确的返回SQL的错误信息, 当把参数送入程序查询时&#xff0c;并且在查询条件为真的情况下返回正常页面&#xff0c;条件为假时程序会重定向到或者返回一个自定义的错…

GICv3 基本规则

目录 1.中断类型 1.1中断标识符 1.2中断如何发送给中断控制器 二、中断状态机 2.1 电平触发 2.2 边沿触发 三、亲和性路由 四、安全模型 4.1 对软件的影响 4.2 对单一安全状态的支持 五、编程模型 本章介绍了符合GICv3架构的中断控制器的基本操作。它还描述了不同…

R语言与数据分析—上(篇幅长,全)

内容过长但详细&#xff0c;分三篇写&#xff0c;总结分享也供日后参考回顾一、什么是R语言R是免费的&#xff0c;是一个全面的统计研究平台&#xff0c;提供了各式各样的数据分析技术&#xff0c;R拥有顶尖的绘图功能二、R语言优点和缺点优点1、有效的数据处理和保存机制2、拥…

LwIP系列--数据包处理和PBUF结构详解

一、目的在之前的博文中我们介绍了LwIP中的内存堆和内存池实现细节以及它们之间的优缺点对比。本篇我们将介绍LwIP中另一个比较重要的知识点&#xff0c;即数据包管理和PBUF结构&#xff1b;个人认为PBUF的设计是LwIP整个源码的亮点之一&#xff08;充分考虑了数据包处理的高效…

泛微发布数字化营销管理平台-九川汇

泛微全程数字化营销管理平台——九川汇&#xff0c;对内可以跨部门、跨组织高效协同&#xff0c;对外借助企业微信快速连接客户。 营销活动是企业运营中重要的一环&#xff0c;数字化工具如何满足企业的营销管理需求&#xff1a; 1、如何有效助力销售活动&#xff1a;帮助销售…

WebServer重写(一):日志库双缓冲和阻塞队列压测对比

目录前言重构动机模块介绍FileUtil&#xff0c;LogFile&#xff0c;LogStream&#xff0c;LoggingAsyncLogging&#xff08;重要&#xff09;压测源码前言 上次参考TinyWebserver的实现思路是&#xff1a;实现一个blockQueue, 然后实现一个日志接口类&#xff0c;这个接口类承…

ROS小车研究笔记1/31/2023 小车硬件结构及键盘移动控制节点

1 小车硬件结构 1 中控设备 上方的单片机用于控制电机运动&#xff0c;搭载wifi模块和电量显示屏。下方为树莓派&#xff0c;安装了ROS系统和Ubuntu系统&#xff0c;用于整个小车控制。显示屏和树莓派相连 2 传感器系统 激光雷达及转换器。激光雷达和转换器相连&#xff0…

【Rust】7. 枚举和模式匹配

7.1 枚举&#xff08;可存储不同类型的值&#xff09; 7.1.1 基本概念 7.1.2 枚举的简洁用法&#xff1a;构造函数 7.1.3 枚举的优势&#xff1a;处理不同类型和数量的数据 枚举成员的类型&#xff1a;字符串、数字类型、结构体、枚举注意&#xff1a;在未将标准库枚举引入当…

Java——两两交换链表中的节点

题目链接 leetcode在线oj题——两两交换链表中的节点 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 题目示例 …

Vue中的$children与$parent讲解

$children与$parent直接演示代码父组件&#xff1a;<template><div><h2>BABA有存款: {{ money }}</h2><button>找小明借钱100</button><br /><button>找小红借钱150</button><br /><button>找所有孩子借钱2…