基于Maven的包依赖管理与仓库配置
基本要求
- 理解并掌握Maven项目的依赖管理机制
- 熟悉Maven安装过程及Maven仓库配置方式
- 掌握通过Maven构建工具来管理项目的第三方依赖
实验原理
Maven基本命令
Maven 运行命令格式如下:
mvn [options] [<goal(s)>] [<phase(s)>]
使用 mvn -h
可以查看到 Maven 所有可用选项。Maven 三个标准生命周期常用的阶段包括:
- clean -
clean
- default -
validate, compile, test, package, verify, install, deploy
- site -
site, site-deploy
例如,打包项目、生成所有文档站点信息并将其部署至仓库的命令为:
mvn clean deploy site-deploy
常用 JAR 打包命令为:
mvn clean package -Dmaven.test.skip=true
-- 跳过测试打包
mvn clean install -Dmaven.test.skip=true
-- 跳过测试打包,并把打好的包上传到本地仓库
mvn clean deploy -Dmaven.test.skip=true
-- 跳过测试打包,并把打好的包上传到远程仓库
Maven 是一款项目管理工具,通过 POM(Project Object Model)文件来定义项目的结构、依赖和构建过程。下面需要应用其两个方面的内容:
- 包依赖管理:Maven使用POM文件中的
元素来管理项目的依赖关系。通过配置依赖项,Maven能够自动下载并集成项目所需的第三方库。 - 仓库配置:Maven仓库是用来存储和管理构建过程中所需库文件的地方。下面将学习如何配置Maven仓库,以便Maven能正确下载项目所需依赖。
Maven Archetype
Archetype 是 Maven 工程的模板工具包,定义了要做的一类项目的基本模型或架构。通过 mvn archetype:generate
命令,开发人员可以很方便地将一类项目的最佳实践应用到自己的项目中。在 Maven 项目中,开发者可以通过 archetype 提供的范例快速入门并了解该项目的结构与特点。一些常见的 Archetype 如下:
- maven-archetype-quickstart:默认的 archetype,Maven 工程项目的样例原型;
- maven-archetype-j2ee-simple:简单的 J2EE 应用程序样例;
- maven-archetype-mojo:Maven 插件项目的示例样例;
- maven-archetype-webapp:Maven 的 Webapp 工程样例。
mvn archetype:generate
命令执行示例如下:
bash
$ mvn archetype:generate \
-DgroupId=cc.synx \
-DartifactId=my-project \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
值得一提的是,与 Spring Boot 项目框架最相近的 Archetype 是 maven-archetype-webapp
,Spring Initializr(https://start.spring.io/)执行与 Archetype 相同的操作,而且对用户更加友好,因此推荐直接使用 Spring Initializr 来创建 SpringBoot 工程。
Settings.xml
settings.xml
文件是 Maven 的配置文件之一,它用于配置 Maven 的全局设置,包括仓库、代理、镜像、插件等。这个文件位于 Maven 的安装目录下的 conf
文件夹中,或者在用户的 Maven 主目录下的 .m2
文件夹中。该文件是可选的,如果用户没有在 Maven 中指定该文件的位置,Maven 会使用默认的设置。以下是 settings.xml
中一些常见配置选项:
<localRepository/>
:指定本地仓库的路径。默认情况下,Maven 会在用户主目录下的.m2
文件夹中创建一个repository
文件夹来存储下载的依赖。<mirrors/>
:用于配置镜像,可以提高构建速度并减轻官方仓库的负载。镜像可以指向其他 Maven 仓库,以加速依赖下载。<proxies/>
:用于配置代理,网络环境需要使用代理来连接 Maven 中央仓库或其他远程仓库时,可以在这里配置代理信息。<profiles/>
:定义一系列的配置文件激活条件,比如根据环境、操作系统等条件来加载不同的配置文件。<servers/>
:用于配置远程仓库的身份验证信息,包括用户名、密码等。这些信息在访问受保护的仓库时需要用到。
Maven私有仓库
软件组件
在软件工程中,“软件组件”通常指的是构成软件系统的独立且可重用的模块或部分。这些组件可以是库、框架、模块、插件等,用于实现特定的功能或服务。
- 库(Library):一个库是一组已经编写好并被打包成可重用形式的代码,提供一组特定的功能。开发者可以在其应用程序中使用这些库,而不必重新实现相同的功能。
- 框架(Framework):框架是一个更大范围的组件,通常包含一组库、工具和指导,用于帮助开发者构建特定类型的应用程序。框架提供了应用程序的基本结构,开发者通过扩展或配置框架来实现具体的业务逻辑。
- 模块(Module):模块是软件系统中的一个独立单元,具有特定的功能。模块可以包含代码、数据、配置等,并且通常设计为可独立开发和测试的单元。
- 插件(Plugin):插件是一种可动态加载到应用程序中以扩展其功能的组件。插件通常是独立开发的,可以根据需要添加到主应用程序中。
Maven仓库管理工具
Maven 仓库管理工具主要用于管理 Maven 仓库中的各种构件(如 JAR 文件、WAR 文件等)和元数据。以下是一些常见的 Maven 仓库管理工具:
- Nexus Repository Manager:Nexus 是一个由 Sonatype 提供的强大的仓库管理和仓库代理工具。它支持 Maven、Docker、npm、NuGet 等多种仓库格式。Nexus 有开源版本(Nexus Repository OSS)和专业版(Nexus Repository Pro)。截至2024年1月,Nexus 运行环境仅支持 JDK 8。
- JFrog Artifactory:Artifactory 是由 JFrog 提供的仓库管理工具,支持 Maven、Gradle、Ivy、Docker、npm、NuGet 等多种仓库格式。Artifactory 有开源版(Artifactory OSS)和付费版本(Artifactory Pro、Artifactory Enterprise)。
- Apache Archiva:Archiva 是 Apache 基金会提供的开源 Maven 仓库管理工具。它支持 Maven 仓库的基本功能,适用于小型项目和团队。
- JitPack:JitPack 是一个基于 Git 的仓库管理服务,它可以将 GitHub 上的项目直接转换为 Maven 仓库。你可以通过 JitPack 将 GitHub 项目发布到 Maven 仓库,以便其他项目可以依赖这些构建产物。
Sonatype Nexus
Sonatype Nexus 是一个用于管理和组织软件构件(例如 JAR 包、WAR 包等)的开源仓库管理系统。它是一个用于构建、部署和管理软件组件的仓库管理器,主要用于帮助团队有效地共享和管理软件构件。Sonatype Nexus 中的一些常见术语包括:
- Repository(仓库):仓库是 Nexus 存储软件构件的地方。Nexus 支持多种类型的仓库,包括 Maven、npm、NuGet、Docker 等。
- Proxy Repository(代理仓库):代理仓库是一个与远程仓库关联的本地缓存。当从远程仓库下载构件时,代理仓库会缓存这些构件,以便在将来的构建中快速访问。
- Group Repository(组合仓库):组合仓库允许将多个仓库组合在一起,并将它们看作一个单独的仓库。这使得在构建中引用多个仓库变得更加简单,同时也提供了对不同类型的仓库的统一访问。
- Lifecycle Management(生命周期管理):Nexus 提供了丰富的生命周期管理功能,包括对构件的版本控制、审计、发布、存储等管理。
雪花算法
雪花算法(Snowflake Algorithm)是由 Twitter 开源的 64 位分布式 ID 生成算法。雪花算法的名称来源于其生成的唯一标识的形状,看起来像雪花的晶体结构。雪花算法的核心思想是利用一个 64 位的整数,其中包含了时间戳、数据中心的标识、机器的标识和一些序列号,以保证在分布式系统中生成的每个 ID 都是唯一的。
- 符号位:1 位,通常为 0。
- 时间戳:41 位,毫秒级时间戳,通过时间戳来保证 ID 的递增性。
- 机器 ID:10 位,存储机器码,5 位 Data Center ID + 5 位 Worker ID,最多可标识集群内 1024 台机器。
- 序列号:12 位,单台机器每毫秒可生成的 ID 数。当同一毫秒内生成的 ID 数量超过了 4096,会等待下一毫秒再生成。
雪花算法的优点是简单且高效,能在分布式环境中生成唯一ID。然而,其依赖于系统时钟,如果系统时钟不稳定或发生回拨,可能会导致ID生成重复或不连续。实际应用时需根据系统特点和需求选择合适的ID生成算法。
实验过程
Maven安装
JDK23下载安装
Maven 编译运行离不开 JDK,在安装 Apache Maven 之前,需要先在系统中安装 JDK,并设置 java 环境变量。Maven 3.9+ 需要 JDK 8 及以上版本支持,本节介绍在 Ubuntu 22.04 LTS 上安装 JDK 17。
[!WARNING]
由于Oracle官网已不再提供JDK17的下载,故我们选择使用JDK23。
- 在 Oracle 官网或使用 wget 在当前目录获取
jdk-23_linux-x64_bin.tar.gz
压缩包,解压后移至/usr/local/
文件夹下。
$ wget https://download.oracle.com/java/23/latest/jdk-23_linux-x64_bin.tar.gz
$ ls
$ sudo tar zxvf jdk-23_linux-x64_bin.tar.gz
$ ls
$ sudo mv jdk-23.0.1/ /usr/local/jdk-23
$ cd /usr/local
$ ls
- 在配置文件
/etc/profile
中配置环境变量JAVA_HOME
、CLASSPATH
。配置完成后执行java -version
查看是否正确安装了 Java。
JAVA_HOME
: JAVA 的安装目录,配置后可通过 $JAVA_HOME
直接获取;
CLASSPATH
: 告知 JVM 在哪些目录下可以找到 JAVA 执行程序所需要的类或者包,供类加载时使用。
$ sudo echo "export JAVA_HOME=/usr/local/jdk-23" >> /etc/profile
$ sudo echo "export PATH=\$PATH:\$JAVA_HOME/bin" >> /etc/profile
$ sudo echo "export CLASSPATH=.:\$JAVA_HOME/lib" >> /etc/profile
$ source /etc/profile # 使配置文件生效
$ java -version
[!NOTE]
编辑系统变量需要root权限!
Maven下载安装
Maven 下载网址:https://maven.apache.org/download.cgi
- 在终端输入
mvn -v
查看本地是否已存在 Maven,若 Maven 已安装,该命令会输出 Maven 版本号。在 Maven 官网或使用 wget 在当前目录下载最新版本的 Maven 压缩包,解压后移至/usr/local/
文件夹下。
$ mvn -v
$ wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
$ sudo tar zxvf apache-maven-3.9.6-bin.tar.gz
$ ls
$ mv apache-maven-3.9.6 /usr/local/apache-maven-3.9
- 在
/etc/profile
文件中配置 maven 环境变量M2_HOME
,配置完成后执行mvn -version
查看是否正确安装了 Maven。
$ sudo echo "export M2_HOME=/usr/local/apache-maven-3.9" >> /etc/profile
$ sudo echo "PATH=\$M2_HOME/bin:\$PATH" >> /etc/profile
$ source /etc/profile # 使配置文件生效
$ mvn -v
# 需要使用 java
Maven仓库配置
- 修改本地仓库地址,Maven 默认仓库地址为
~/.m2/repository
。推荐将本地仓库配置至 Maven 安装目录下,需要在文件${M2_HOME}/conf/settings.xml
中配置<localRepository>
。
$ pwd
$ sudo mkdir local_repository
$ sudo vim conf/settings.xml
<?xml version="1.0" encoding="UTF-8"?>
...
<localRepository>/usr/local/apache-maven-3.9/local_repository</localRepository>
# 在 settings.xml 53行左右
- Maven 远程仓库默认为 Maven Central Repository,可以在
settings.xml
中配置远程镜像仓库为国内阿里云镜像仓库,提高 Jar 包下载的速度和稳定性。配置settings.xml
完成后保存退出。
# 在 settings.xml 160行处添加镜像源,需要保证镜像源标签在原仓库标签之前
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
基于Maven构建雪花算法组件
创建Java项目
- 使用 Maven Archetype 创建一个基本的 Java 项目,本节将基于该项目实现雪花算法并将其构建成组件发布。创建项目时需要配置
groupId
、artifactId
。
$ mvn archetype:generate -DgroupId=cc.synx -DartifactId=snowflake -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
$ ls -F
$ cd snowflake
$ tree
- pom.xml 中 package 标签为 jar,使用 Maven 可以将该项目打为 JAR 包使用。注意,当前pom.xml中没有打包插件
<build/>
,生成的 JAR 包需要指定主启动类方可运行。
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cc.synx</groupId>
<artifactId>snowflake</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>snowflake</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
实现雪花算法
- 在
App.java
同级目录下创建SnowflakeUtil.java
,添加如下代码:
package cc.synx;
public class SnowflakeUtil {
private static final long EPOCH = 1704038400000L; // 设置起始时间戳(2024-01-01 00:00:00)
private long workerId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeUtil(long workerId) {
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds.");
}
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & 4095;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - EPOCH) << 22) | (workerId << 12) | sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
}
- 编辑
App.java
的main
方法,调用SnowflakeUtil
的nextId()
方法。
package cc.synx;
public class App {
public static void main(String[] args) {
SnowflakeUtil snowflakeUtil = new SnowflakeUtil(11);
System.out.println("first snowflake id is:" + snowflakeUtil.nextId());
}
}
构建运行项目
- 在
pom.xml
同级目录下,通过Maven工具构建项目并打包成JAR。
ls -F
mvn clean
mvn package
- 成功执行
mvn clean package
命令后,在pom.xml
同级目录下生成了target
目录,包括Java字节码文件和生成的JAR包snowflake-1.0-SNAPSHOT.jar
。
ls -F
cd target
ls -F
- 使用
java -jar xxx.jar
命令运行JAR包,发现该JAR包没有指定主执行类,因此运行时需要指定Java MainClass。
java -jar snowflake-1.0-SNAPSHOT.jar
java -cp snowflake-1.0-SNAPSHOT.jar cc.synx.App
- 执行如下Maven命令也可运行Java项目:
mvn exec:java -Dexec.mainClass="cc.synx.App"
将JAR包存储至本地仓库
- 在
pom.xml
同级目录下执行mvn install
命令,将JAR包安装至本地仓库中。
mvn install:install-file -Dfile=target/snowflake-1.0-SNAPSHOT.jar -DgroupId=cc.synx -DartifactId=snowflake -Dversion=1.0 -Dpackaging=jar
上述命令各参数解释如下:
-Dfile
:指定要安装的 JAR 文件的路径。
-DgroupId
:指定组 ID。
-DartifactId
:指定 artifact ID。
-Dversion
:指定版本号。
-Dpackaging
:指定打包类型(在这种情况下是 JAR)。
- 查看 Maven 本地仓库是否存在 Snowflake 组件包。
$ cd /usr/local/apache-maven-3.9/local_repository/
$ ls -F
cc/ ... # snowflake 组件在 cc/synx 目录下
Snowflake
组件在本地仓库安装成功后,其他Maven项目在pom.xml
文件中可以通过<dependency></dependency>
标签引入该组件。
<dependency>
<groupId>cc.synx</groupId>
<artifactId>snowflake</artifactId>
<version>1.0</version>
</dependency>
配置Maven私有仓库
构建Maven私有仓库
[!NOTE]
Nexus 官网:https://www.sonatype.com/
sonatype/nexus 镜像网址:https://hub.docker.com/r/sonatype/nexus3/
- 本节将使用 Nexus Repository Manager 3 仓库管理工具来搭建独立的 Maven 私有仓库。安装 Nexus 的机器(必须有 JDK8,Nexus 3.x 只能在 JDK8 环境下运行)和构建 Maven 项目的机器不要求一致,若通过官网下载 tar.gz 包来安装 nexus,参考第二、三步。若没有 JDK8 环境或其他诉求,参考第四步使用 Docker 安装。
- 下载官网提供的 Nexus 压缩包,解压并移动至 /usr/local 目录。
$ ls
$ sudo tar xxzvf nexus-3.64.0-04-unix.tar.gz
$ sudo mv nexus-3.64.0-04 /usr/local/nexus3
$ cd /usr/local
$ ls -F
- Nexus 使用 Java 开发,运行 Nexus 3.x 前需要确保系统中安装了 JDK8,并根据系统硬件配置调整 Nexus 的运行时内存区大小。
$ cd /usr/local/bin
$ sudo vim nexus.rc
$ ./nexus start
我们使用阿里云ECS,在Docker中安装Nexus
- 首先需要确保阿里云ECS开放了8081端口。在安全组->管理规则中开放8081端口,然后最好重启实例。
- 使用Docker安装Nexus时,须确保系统中安装了Docker,安装完成后使用docker ps查看Nexus容器是否正常运行。
$ docker run -d \
-p 8081:8081 \
-v /root/nexus-data:/var/nexus-data \
-e INSTALL4J_ADD_VM_PARAMS="-Xms128m -Xmx1024m" \
--name nexus \
sonatype/nexus3
- Nexus默认以8081端口开放,访问
http://<server-ip>:8081
查看Nexus的页面,勿开启安全检查。
点击Sign in,Username输入admin
[!NOTE]
password查看方式:
docker exec -it nexus bash bash-4.4$ cd /opt/sonatype/sonatype-work/nexus3/ bash-4.4$ cat admin.password 868b44bb-8776-4dcf-9a65-09d6ace80ba4
首次登录成功后需要修改密码。
- Nexus登陆成功后,点击Create repository新建Maven私有仓库。
- 仓库类型选择
maven2(hosted)
类型,仓库名填入my-maven-repo
,仓库制品类型选择Release
,完成创建。
将组件上传至Maven私有仓库
- 编辑Maven的
setting.xml
文件,添加私有仓库的配置信息。在<servers/>
标签中添加仓库名、账号密码,在<mirrors/>
和<profiles/>
标签中添加仓库URL、仓库ID等,最后在<activeProfiles/>
标签中使私有仓库生效。
<servers>
<server>
<id>my-maven-repo</id>
<username>admin</username>
<password>password</password> <!-- 仓库密码 -->
</server>
<!-- 其他服务器 -->
</servers>
<mirrors>
<mirror>
<id>my-maven-repo</id>
<url>http://server-id:8081/repository/my-maven-repo/</url>
<mirrorOf>*</mirrorOf>
</mirror>
<!-- 其他镜像仓库 -->
</mirrors>
<profiles>
<profile>
<id>my-maven-repo</id>
<repositories>
<repository>
<id>my-maven-repo</id>
<url>http://server-id:8081/repository/my-maven-repo/</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>my-maven-repo</activeProfile>
</activeProfiles>
- 保存退出后,在snowflake项目的pom.xml中添加上传远程仓库的配置。
$ cat snowflake/pom.xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cc.synx</groupId>
<artifactId>snowflake</artifactId>
<packaging>jar</packaging>
<version>1.0</version> <!-- 将version中snapshot去掉 -->
<name>snowflake</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>my-maven-repo</id>
<url>http://server-id:8081/repository/my-maven-repo/</url>
</repository>
</distributionManagement>
</project>
- 将之前构建的Java组件上传至私有仓库。
$ mvn deploy
- 上传完成后,在Nexus页面上可以查看到已上传的
snowflake-1.0
组件。
基于私有仓库构建项目
- 参考前文,构建新的Maven项目
- 在pom.xml中引入snowflake依赖,并在main方法中使用SnowflakeUtil工具类。
<dependencies>
<dependency>
<groupId>cc.synx</groupId>
<artifactId>snowflake</artifactId>
<version>1.0</version>
</dependency>
...
</dependencies>
main 方法内容如下:
public static void main(String[] args) {
SnowflakeUtil snowflakeUtil = new SnowflakeUtil(11);
System.out.println("snowflakeId:" + snowflakeUtil.nextId());
}
构建 Maven 的 settings.xml 与 前文给定的 settings.xml 一致即可。
不要求使用同一台设备,如果使用同一台设备,为更好的展示效果,尝试先将 Maven 本地仓库的 snowflake 依赖移除,命令如下:
$ sudo mvn dependency:purge-local-repository -DmanualIncludes="cc.synx:snowflake:1.0"
- 完成新项目的构建运行。
- 以下是输出格式:
snowflakeId:405200000000000000