写点什么

一文带你搞定 Maven 全功能

作者:Java你猿哥
  • 2023-04-23
    湖南
  • 本文字数:5980 字

    阅读完需:约 20 分钟

一文带你搞定Maven全功能

在一次需求迭代中,同事要求我把写好的 RPC 接口打好包上传到公司私服上,我人直接当场懵逼住了。


突然发现自己对于 Maven 仅仅是处于最基础的使用阶段,不仅不知道背后的一些原理,甚至连一些常见的概念都不是很清晰,仅仅会使用 Maven 构建项目,引入依赖,打包等最基础的操作,所以连忙补补课,成功完成了需求,并且在此处总结一下 Maven 中稍微进阶一点的知识。

依赖

依赖是我们在使用 Maven 构建项目时最常使用的功能,通过依赖标签,我们可以直接从 Maven 仓库中引入对应的 Jar 包,无需手动再将 Jar 添加到目录下了,可谓是十分方便,不过我们除了使用,还需要考虑多模块下依赖之间的关系。

依赖配置

这个大家应该都很熟悉了,通过<dependency>标签引入 Maven 依赖

<dependencies>		<!-- servlet包 -->     <dependency>          <groupId>javax.servlet</groupId>          <artifactId>javax.servlet-api</artifactId>     </dependency></dependencies>
复制代码

引入依赖之后,刷新一下 Maven 依赖就可以引入相关的 Jar 包了。

依赖传递

依赖具有传递性,当我们引入了一个依赖的时候,就会自动引入该依赖引入的所有依赖,依次往下引入所有依赖。

比如我们引入了 Druid 数据库连接池的 SpringBoot-Starter,那么就会自动引入一些依赖


如图,我们仅仅引入了 druid-spring-boot-starter 依赖,就自动引入了该依赖依赖的依赖。总而言之就是套娃就完事了。

我们将这三个依赖称为间接引入的依赖,而我们在<dependency>标签中引入的依赖称为直接依赖,那么如果这两个重复了并且版本不一样的话会怎么办呢,最后引入的到底是哪个版本呢,还是说都会引入呢?

如果重复了,遵从以下规则


简单来说,就是越在外层的优先级越高,如果同级的就按照配置顺序,配置顺序靠前的覆盖配置顺序靠后的。

可选依赖

可选依赖指对外隐藏当前所依赖的资源

<dependency>	<groupId>junit</groupId>	<artifactId>junit</artifactId>	<version>4.12</version>	<optional>true</optional></dependency>
复制代码

配置了该选项之后,间接依赖就失效了。

排除依赖

排除依赖指主动断开间接依赖的资源

<dependency>	<groupId>junit</groupId>	<artifactId>junit</artifactId>	<version>4.12</version>	<exclusions>		<exclusion>			<groupId>org.hamcrest</groupId>			<artifactId>hamcrest-core</artifactId>		</exclusion>	</exclusions></dependency>
复制代码

配置了该选项之后,间接依赖也会失效。

排除依赖和可选依赖的区别:

可选依赖是依赖提供者设置的,比如我们引入了 Durid,那么该选项由 Durid 开发者设置

排除依赖由依赖引入者设置,比如我们引入了 Durid,那么我们可以设置该选项

依赖范围

依赖的 jar 默认情况可以在任何地方使用,可以通过 scope 标签来改变依赖的作用范围。


主代码指的是 main 文件夹下的代码,测试代码指的是 test 文件夹下的代码(就那个绿色的玩意),打包指的是 maven package 指令执行时是否将 Jar 包打包。

其实如果我们偷懒的话,全部都默认也不是不可能,不过为了我们程序代码的可读性与简洁性,还是按照规范来比较好。

生命周期与插件

项目构建生命周期

Maven 项目构建生命周期描述的是一次构建过程经历了多少个事件,我们可以把生命周期当成一个人的年龄。

Maven 将生命周期划分为三个大阶段,类似于人类的婴儿,青年,入土

  • clean:清理工作

  • default:核心工作,例如编译,测试,打包,部署

  • site:产生报告,发布站点

第一个和第三个周期比较简单,我们重点介绍一下 default 阶段

先上一张劝退图


以上就是 defalut 阶段完整的生命周期,其中标红的地方,是几个比较重要的周期,在 Idea 的 Maven 工具中也能体现出来


当我们在 Idea 中点击这几个生命周期时,Maven 会自动将之前所有的生命周期都执行到,就类似于如果我 18 岁了,那么我肯定经历过 8 岁。

插件

插件就是 Idea 中 Maven 工具的 Plugins 部分


通过 pom 文件中的<build></build>标签引入新的插件

<build>        <plugins>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <version>3.1</version>                <configuration>                    <source>1.8</source>                    <target>1.8</target>                    <encoding>UTF-8</encoding>                </configuration>            </plugin>        </plugins></build>
复制代码

那么什么是插件呢?

  • 插件与生命周期内的阶段绑定,在执行到对应生命周期时执行对应的插件功能

  • 默认 maven 在各个生命周期上绑定有预设的功能

  • 通过插件可以自定义其他功能

  • <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.2.1</version> <executions> <execution> <goals> <goal>jar</goal> </goals> <phase>generate-test-resources</phase> </execution> </executions> </plugin> </plugins> </build> 复制代码

  • 上述自定义插件的作用指的是在 generate-test-resources 生命周期执行打 jar 包的操作。

其实简单的说,生命周期就是一个人的年龄阶段,而插件就是每个人在每个年龄需要做的事情

总结:


Maven 将一个项目构建的过程分为一长串连续的生命周期,在对应的生命周期会通过插件完成对应的事件,通过使用 Maven 的生命周期,我们可以获得我们需要的功能,可能是打 jar 包,可能是安装到本地仓库,可能是部署到私服。

模块聚合

当使用 Maven 进行多模块开发的时候,有可能出现 A 模块依赖 B 模块,B 模块依赖 C 模块,那么我们如果想对 A 模块打包,那么就要先打包 C 模块,再打包 B 模块,最后打包 A 模块才能成功,否则会报错,并且,如果 C 模块更新了,我们也要手动更新所有依赖 C 模块的模块,这样是及不方便的,Maven 为了更好的进行多模块开发,提供了模块聚合的功能。

作用:聚合用于快速构建 Maven 工程,一次性构建多个项目/模块

  • 使用步骤,我们用开源项目 ruoyi 的项目结构来看一下聚合在 ruoyi 中的使用


  • RuoYi-Vue 父模块的 pom 文件

  • <!--聚合的所有模块--> <modules> <module>ruoyi-admin</module> <module>ruoyi-framework</module> <module>ruoyi-system</module> <module>ruoyi-quartz</module> <module>ruoyi-generator</module> <module>ruoyi-common</module> </modules> <!--打包类型定义为 pom--> <packaging>pom</packaging> 复制代码

  • 直接对打包类型为 pom 的模块进行生命周期的管理,Maven 会自动帮我们管理聚合的所有模块的生命周期,操作顺序跟依赖顺序有关系。

模块继承

还是在多模块项目开发中,多个子模块可能会引入相同的依赖,但是他们有可能会各自使用不同的版本,版本问题,有可能会导致最后构建的项目出问题,所以我们需要一种机制,来约定子模块的相关配置,于是就有了模块继承

作用:通过继承可以实现在子工程中沿用父工程中的配置

实现步骤:还是以 ruoyi 为例

  1. 在子工程中声明其父工程坐标与对应的位置

  2. <parent> <artifactId>ruoyi</artifactId> <groupId>com.ruoyi</groupId> <version>3.8.1</version> </parent> 复制代码

  3. 在父工程中定义依赖管理

  4. <dependencyManagement> <dependencies> <!-- SpringBoot 的依赖配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.5.8</version> <type>pom</type> <scope>import</scope> </dependency> <!-- 阿里数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> <!-- SpringBoot 集成 mybatis 框架 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis-spring-boot.version}</version> </dependency> <!-- pagehelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.boot.version}</version> </dependency> </dependencies> </dependencyManagement> 复制代码

  5. 定义完成之后,子工程相关的依赖就无需定义版本号,会直接使用父工程的版本号

  6. <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> </dependency> 复制代码

继承除了依赖版本号之外,还会继承一些资源,如下图


属性

在 Maven 中,对于有些依赖可能需要保证相同的版本,比如 Spring 相关依赖,那么我们就需要一个机制来保证这些依赖的版本都相同,我们可以使用 Maven 中的属性,类似编程语言的全局变量。

Maven 中有很多属性:

  1. 自定义属性

  2. 内置属性

  3. Setting 属性

  4. Java 系统属性

  5. 环境变量属性

此处我们重点讲解一下

自定义属性

作用:将一些字符串定义为变量,方便统一维护

使用步骤:还是以 ruoyi 为例

  1. 定义自定义属性

  2. <properties> <ruoyi.version>3.8.1</ruoyi.version> </properties> 复制代码

  3. 调用:${xxx.yyy}

  4. <groupId>com.ruoyi</groupId> <artifactId>ruoyi</artifactId> <version>${ruoyi.version}</version> 复制代码

内置属性

作用:使用 Maven 内置属性,快速配置一些文件

${basedir}${version}
复制代码

Setting 属性

作用:使用 Maven 配置文件 setting.xml 中的标签属性,用于动态配置

${settings.localRepository}
复制代码

Java 系统属性

作用:读取 Java 系统属性

调用格式

${user.home}
复制代码

系统属性查询方式

mvn help:system
复制代码

环境变量属性

作用:使用 Maven 环境变量

${env.JAVA_HOME}
复制代码

版本管理

对于我们的项目来说,如果我们将其放到一些 Maven 仓库中,那么就需要对其进行版本控制,我们可以看一下一些开源项目的 Maven 官网上的版本。


pom 文件配置

<version>1.0.0.RELEASE</version>
复制代码

工程版本号约定


工程版本


环境配置

一个项目,开发环境、测试环境、生产环境的配置文件必然不同,那么 Maven 就需要进行多环境配置管理

Maven 多环境对应 Idea 中 Maven 工具的 Profiles


配置文件:通过<profiles>配置文件配置,一个 profile 代表一个可选项

<profiles>        <profile>            <id>local</id>            <properties>                <!-- 环境标识,需要与配置文件的名称相对应 -->                <profiles.active>local</profiles.active>                <logging.level>debug</logging.level>            </properties>        </profile>        <profile>            <id>dev</id>            <properties>                <!-- 环境标识,需要与配置文件的名称相对应 -->                <profiles.active>dev</profiles.active>                <logging.level>debug</logging.level>            </properties>            <activation>                <!-- 默认环境 -->                <activeByDefault>true</activeByDefault>            </activation>        </profile>        <profile>            <id>test</id>            <properties>                <profiles.active>test</profiles.active>                <logging.level>debug</logging.level>            </properties>        </profile>        <profile>            <id>prod</id>            <properties>                <profiles.active>prod</profiles.active>                <logging.level>warn</logging.level>            </properties>        </profile></profiles>
复制代码

然后我们在 application.yml 配置文件中设置即可,之后通过设置 maven 的 profiles,就可以动态调整环境了。


私服

Maven 私服指的是企业自己搭建的 Maven 仓库,通过 Maven 私服,第三方组织可以把自己组织内部的 Maven 依赖安装到私服上,提供给组织内部使用,搭建完私服之后,通过配置 Maven,我们不止可以从中央仓库中获取 Maven 依赖,还可以从私服中获取 Maven 依赖。

下图是获取资源的过程,中央仓库的资源会从中央仓库获取,其他资源会从私服仓库获取


私服搭建

通过 Nexus 搭建私服

Nexus 是 Sonatype 公司的一款 Maven 私服产品

下载地址:Download (sonatype.com)


私服仓库介绍

安装好之后我们来看一下私服默认的仓库列表


可以将这些仓库分为三大类

  • 宿主仓库 hosted:保存无法从中央仓库获取的资源 自主研发 第三方非开源项目

  • 代理仓库 proxy 代理远程仓库,通过 nexus 访问其他公共仓库

  • 仓库组:将若干个仓库组成一个群组,简化配置,它仅仅是一种配置,不是真实的仓库 比如我们可以将二课项目相关的依赖放到一个仓库组中,将抽奖项目的依赖放到一个仓库组中

创建私服仓库

点击 create repository


选择 maven2(hosted)


填入仓库名称


创建完之后在仓库列表可见,将新建的仓库加入 maven-public 仓库组,之后通过该仓库组的 url 访问


点击 maven-public 仓库组


本地仓库访问私服配置

配置本地仓库访问私服的权限(setting.xml 文件),如果你想从这个仓库中获取或者部署资源,那么就需要 server 配置来验证权限,此处可以是不同的账号密码,不同的用户对于仓库的权限也不同。

配置 Servers

<servers>	<server>		<id>ticknet-release</id>		<username>admin</username>		<password>admin</password>	</server>	<server>		<id>ticknet-snapshots</id>		<username>admin</username>		<password>admin</password>	</server></servers>
复制代码

配置 setting.xml 的 Profiles

    <profiles>        <profile>            <id>artifactory</id>            <repositories>                <repository>                    <snapshots>                        <enabled>false</enabled>                    </snapshots>                    <id>repo</id>                    <name>repo</name>                    <url>xxxx</url>                </repository>                <repository>                    <snapshots/>                    <id>snapshots</id>                    <name>snapshots-only</name>                    <url>xxxx</url>                </repository>            </repositories>        </profile>    </profiles>
复制代码

此处的 URL 通过


这个 copy 按钮获取。

配置激活 profiles

 <activeProfiles>        <activeProfile>artifactory</activeProfile> </activeProfiles>
复制代码

之后就可以从私服获取资源了

上传资源到私服

配置项目 pom 文件

<distributionManagement>	<repository>		<id>ticknet-release</id>		<url>http://localhost:8081/repository/ticknet-release/</url>	</repository>	<snapshotRepository>		<id>ticknet-snapshots</id>		<url>http://localhost:8081/repository/ticknet-release/</url>		</snapshotRepository></distributionManagement>
复制代码

配置完执行生命周期的 deploy 即可

OK,大功告成

用户头像

Java你猿哥

关注

一只在编程路上渐行渐远的程序猿 2023-03-09 加入

关注我,了解更多Java、架构、Spring等知识

评论

发布
暂无评论
一文带你搞定Maven全功能_Java_Java你猿哥_InfoQ写作社区