前言

在软件开发中,一个项目的依赖管理,项目结构以及项目构建流程对于不同的开发者来说可能有一套属于自己的方式,对于独立开发来说这不是什么大问题,但是一个人的力量往往是有限的,所以我们不可避免的要进行团队协作,如果每个开发者都坚守一套自己的规则,那是既不利于团队开发的。而 maven 就为我们提供了一套很好的解决方案,maven 是 apache 开源基金会的一个项目,它为 java 语言提供了一个很好的第三方依赖管理以及项目管理的解决方案。对于其他编程语言都有自己的第三方依赖管理,比如 python 的 pip,js 的 npm 等,这些依赖管理工具能让我们站在巨人的肩膀上生产出更好的作品来回馈社区。

maven 项目结构

1
2
3
4
5
6
7
8
9
10
11
12
项目文件夹
├── src 源文件
│ ├── main
│ │ ├── java 主程序
│ │ └── resources 静态资源
│ └── test
│ └── java 测试代码
├── target 编译好的class文件和jar包等
│ ├── classes
│ ├── ...
│ └── xxx.jar
└── pox.xml

maven 依赖管理

maven 使用 xml 来配置项目工程,在项目中的 pom.xml 文件中配置项目的依赖的信息,在 dependencies 标签中配置所需要的 dependency,格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
  • groupId 标签为组织名称,如果组织下项目比较多需要细分的话则可以在后面添加项目名称
  • artifactId 标签为项目或模块名称
  • version 标签为版本

maven 依赖传递

如果当 A 工程导入了 B 工程,而 B 工程导入了 C 工程,那么 A 工程中在构建打包时也会打包 C 工程所需的依赖

如果 A 工程不需要 C 工程的某个依赖,可以使用 exclusions 标签来排除这个工程中的依赖:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>priv.ana</groupId>
<artifactId>maven-projectB</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>

maven 依赖范围

在 dependency 标签中使用 scope 标签可以配置每个依赖的依赖范围,格式如下:

1
2
3
4
5
6
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>3.0.3</version>
<scope>test</scope>
</dependency>

依赖范围有以下三种:

  • 主程序范围,main 文件夹
  • 测试程序范围,test 文件夹
  • 打包运行范围,jar 包

scope 标签的常见值如下:

主程序 测试 打包(运行)
compile(默认) Y Y Y
test - Y -
provided Y Y -
runtime - Y Y

maven 构建生命周期

maven 有以下三个标准的生命周期:

  1. Clean 生命周期:
    • clean:删除目标目录中的编译输出文件。
  2. Default 生命周期:
    • validate:验证项目的正确性,例如检查项目的版本是否正确。
    • compile:编译项目的源代码。
    • test:运行项目的单元测试。
    • package:将编译后的代码打包成可分发的格式,例如 JAR 或 WAR。
    • verify:对项目进行额外的检查以确保质量。
    • install:将项目的构建结果安装到本地 Maven 仓库中,以供其他项目使用。
    • deploy:将项目的构建结果复制到远程仓库,以供其他开发人员或团队使用。
  3. Site 生命周期:
    • site:生成项目文档和站点信息。
    • deploy-site:将生成的站点信息发布到远程服务器,以便共享项目文档。

maven 继承

maven 中可以实现工程与工程之间的继承关系,比如当我们开发多个模块中存在很多的共同依赖则可以将这些依赖抽取成一个父工程,然后让各个模块成为它的子工程,所以说一个父工程就是用来进行多个模块的依赖管理的,与子工程不一样的是父工程的打包方式需要为 pom,以下为样例:

父工程 xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
<relativePath/>
</parent>
<groupId>priv.ana</groupId>
<artifactId>maven-project-parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>maven-project-parent</name>
<url>http://maven.apache.org</url>
<dependencies> <!-- 共同依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>

子工程 xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>
<parent>
<groupId>priv.ana</groupId>
<artifactId>maven-project-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>maven-project-part1</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>maven-project-part1</name>
<url>http://maven.apache.org</url>
</project>

子工程的 parent 标签中需要指定父工程 pom.xml 位置,如果子父工程的结构如下则可以使用以上配置:

1
2
3
4
5
6
父工程文件夹
├── 子工程1文件夹
├── 子工程2文件夹
├── 子工程3文件夹
├── ...
└── pox.xml

如果这整个工程为一个 springboot 工程,则可以在父工程的 parent 标签中指定 springboot 的父工程,并且将 relativePath 标签设置为空,表示需要到仓库中拉取。

maven 依赖版本管理

在整个项目当中如果分了模块来进行开发,那么模块与模块之间就会存在版本不同的问题,这样不便于管理和维护,所以在整个项目的父工程中可以使用 dependencyManagement 标签进行依赖版本管理,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<properties>
<jjwt.version>0.12.3</jjwt.version>
<pagehelper-spring-boot-starter.version>1.4.7</pagehelper-spring-boot-starter.version>
<mybatis-spring-boot.version>3.0.3</mybatis-spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>${mybatis-spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

同时,如果管理的依赖过多,依赖的版本号会散落在各处,使用 properties 标签可以将版本号等信息集中起来方便管理。
这样,后续在子工程中使用到父工程管理的依赖时就可以不用指定版本号来使用父工程管理好的版本了。

maven 聚合

多个子工程之间如果互相依赖,那么在打包时需要将这些工程按照依赖的顺序先后打包,如果需要手动进行这些操作将会非常的繁琐而且还需要我们去分析这些模块之间的依赖关系,而 maven 中的聚合可以解决这个问题,在父工程的 pom.xml 文件中配置 modules 标签然后对父工程执行标准的生命周期,则可以实现多模块的构建,以下为样例:

1
2
3
4
5
<modules>
<module>maven-project-part1</module>
<module>maven-project-part2</module>
<module>maven-project-part3</module>
</modules>

maven 私服

当我们开发好的模块需要给其他开发成员使用时,就需要将编译好的文件上传到 maven 仓库中,但是 maven 的中央仓库我们并没有权限上传代码,所以我们就需要建立一个 maven 的私服仓库。

Nexus 是一个可以使用 docker 部署的第三方依赖仓库,安装好 docker 后使用命令:

1
docker run -d -p 8081:8081 --name nexus -v /docker/nexus/nexus-data:/nexus-data --restart=always sonatype/nexus3

此命令会下载 Nexus 的镜像并启动容器,将容器的 8081 端口映射到主机的 8081 端口,并将容器的/nexus-data 目录挂载到主机的/docker/nexus/nexus-data 目录。
然后就可以通过 http://IP:8081 访问管理面板了。

如果出现启动失败可以使用 docker logs -f nexus 查看日志,一般的问题为容器没有权限访问主机的/docker/nexus/nexus-data 目录,可以使用chmod 777 /docker/nexus/nexus-data命令给予权限,然后重启容器即可。

默认账号为 admin,密码在文件/nexus-data/admin.password 中,也就是主机的/docker/nexus/nexus-data/admin.password,第一次登录之后需要修改密码。

私服仓库

默认的私服仓库有三个,分别为:

  • maven-central:maven 中央仓库的代理,通过这个仓库下载的包会缓存在这个仓库中,以便于下次使用
  • maven-releases:发布版的仓库,如果版本号后面什么都没加或者添加了 RELEASE 则上传到这个仓库中
  • maven-snapshots:快照版的仓库,如果版本号后面添加了 SNAPSHOT 则上传到这个仓库中

除了这三个仓库之外还有一个仓库组:

  • maven-public:通过这个仓库组下载依赖时会从三个仓库中搜索相应的包,在 maven 配置中设置这个下载源就可使用自己开发的依赖以及中央仓库中的依赖

nexus 除了支持 maven 的仓库之外还支持 docker,apt,npm,pip 的仓库,可以按需使用

maven 配置

maven 默认连接的是中央仓库,需要在 maven 的 settings.xml 和项目的 pom.xml 添加配置才能连接私服仓库。

settings.xml 需要使用 servers 配置仓库的账号密码,然后使用 mirrors 更改下载源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<servers> <!--仓库的账号和密码-->

<server>
<id>maven-releases</id>
<username>账号</username>
<password>密码</password>
</server>

<server>
<id>maven-snapshots</id>
<username>账号</username>
<password>密码</password>
</server>

<server>
<id>maven-public</id>
<username>账号</username>
<password>密码</password>
</server>

</servers>
<mirrors> <!--下载源地址-->

<mirror>
<id>maven-public</id>
<mirrorOf>*</mirrorOf>
<url>http://192.168.100.88:8081/repository/maven-public/</url>
</mirror>

</mirrors>
<profiles> <!--指定快照版本的依赖依然允许使用-->

<profile>
<id>allow-snapshots</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>

<repository>
<id>maven-public</id>
<url>http://192.168.100.88:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>

</repositories>
</profile>

</profiles>
</settings>

项目中的 pom.xml 中需要使用 distributionManagement 添加 releases 和 snapshots 仓库的地址:

1
2
3
4
5
6
7
8
9
10
<distributionManagement>
<repository>
<id>maven-releases</id>
<url>http://192.168.100.88:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-snapshots</id>
<url>http://192.168.100.88:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>