一、什么是Maven?
Maven 是一个流行的项目管理工具和构建工具,可以对 Java 项目进行构建、依赖管理。简单来说,它就像一个“助手”,使得项目的开发和管理变得更加简单和高效。
其它知识点补充:
项目管理工具:指的是一种软件,帮助开发者组织、管理和跟踪项目的进展。使用 Maven,可以轻松创建、配置和维护 Java 项目。
构建:是指将源代码转换为可以运行的程序的过程。Maven 可以自动化这个过程,它会根据指定的配置文件(通常是 pom.xml
)来编译代码、打包程序、运行测试等。
依赖管理:是指处理项目中使用的库或其他组件(称为依赖)的过程。很多 Java 项目会依赖于其他库来实现某些功能。Maven 可以自动下载这些依赖,并确保它们的版本兼容,这样开发者就不需要手动管理这些库的版本和下载。
二、Maven有什么用?我们为什么要学Maven?
Maven 有什么用
项目的自动构建,包括代码的编译、测试、打包、安装、部署等操作。
依赖管理,项目使用到哪些依赖,可以快速完成导入,不需要手动导入jar包。
我们为什么要学 Maven?
简单一句话,你不学maven就别想学别的东西(例如springcloud)!
三、Maven项目结构
而下面的pom.xml则是Maven的核心配置,也是整个项目的所有依赖、插件、以及各种配置的集合,它也是使用XML格式编写的,一个标准的pom配置长这样:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>BookManage</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
pom配置解释:
project::根节点。
modelVersion::定义了当前模型的版本,不用管它。
groupId、artifactId、version::这三个元素合在一起,用于唯一区别每个项目,别人如果需要将我们编写的代码作为依赖,那么就必须通过这三个元素来定位我们的项目,我们称为一个项目的基本坐标,所有的项目一般都有自己的Maven坐标,因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了,无需再下载Jar文件,而是Maven自动帮助我们下载依赖并导入。
groupId
一般用于指定组名称,命名规则一般和包名一致,比如我们这里使用的是org.example
,一个组下面可以有很多个项目。artifactId
一般用于指定项目在当前组中的唯一名称,也就是说在组中用于区分于其他项目的标记。version
代表项目版本,随着我们项目的开发和改进,版本号也会不断更新,我们可以手动指定当前项目的版本号,其他人使用我们的项目作为依赖时,也可以根据版本号进行选择(这里的SNAPSHOT代表快照,一般表示这是一个处于开发中的项目,正式发布项目一般只带版本号)
properties:这里一般都是一些变量和选项的配置,我们这里指定了JDK的源代码和编译版本为17,同时下面的源代码编码格式为UTF-8,无需进行修改。
四、Maven依赖导入
<dependencies>
//里面填写的就是所有的依赖
</dependencies>
举例说明(以插入Lombok依赖为例):
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.36</version>
</dependency>
五、Maven依赖作用域
除了三个基本的属性用于定位坐标外,依赖还可以添加以下属性:
type:依赖的类型,对于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值为jar
scope:依赖的范围
optional:标记依赖是否可选
exclusions:用来排除传递性依赖(一个项目有可能依赖于其他项目,就像我们的项目,如果别人要用我们的项目作为依赖,那么就需要一起下载我们项目的依赖,如Lombok)
1. type
作用:定义依赖的类型,对应项目的打包类型(
packaging
)。默认值:
jar
。使用场景:当依赖的类型不是
jar
时,例如war
(Web 应用)、pom
(父项目定义)、zip
等,需要显式声明。示例:
<dependency> <groupId>org.example</groupId> <artifactId>example-artifact</artifactId> <version>1.0.0</version> <type>war</type> </dependency>
2. scope(重点)
作用:定义依赖的作用范围。主要范围包括:
compile
(默认值):编译、测试和运行时都需要。provided
:编译和测试时需要,但运行时由容器(如 Tomcat)提供。runtime
:运行和测试时需要,编译时不需要。test
:仅测试时需要,编译和运行时不需要。system
:类似于provided
,但需要本地提供依赖路径(几乎不用)。import
:用于引入 BOM(Bill of Materials)依赖管理。
示例:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
3. optional
作用:标记依赖是否为可选依赖,避免被传递到依赖的消费者(下游项目)。
默认值:
false
。使用场景:当依赖是可选功能模块,不想影响下游项目时。
示例:
<dependency>
<groupId>org.example</groupId>
<artifactId>optional-lib</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
4. exclusions
作用:用于排除传递性依赖,防止不必要的依赖被引入。
使用场景:当依赖的项目中包含的某些传递性依赖与你的项目冲突时。
示例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
六、Maven安装、可选和排除
1、Maven 安装
问题导入:如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢?
先创建一个用于测试的简单项目:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>TestMaven</artifactId>
<version>1.0-SNAPSHOT</version>
...
</project>
public class TestUtils {
public static void test() {
System.out.println("家人们谁懂啊,蒸虾头,怎么会有人想吃我家鸽鸽下的蛋");
}
}
接着我们点击右上角的Maven选项,然后执行install
或直接在命令行中输入mvn install
来安装我们自己的项目到本地Maven仓库中。
接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了,只需要填写和这边一样的坐标:
<dependency>
<groupId>com.test</groupId>
<artifactId>TestMaven</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
接着我们就可以在项目中直接使用了:
public static void main(String[] args) {
TestUtils.test();
}
2、Maven 中的可选依赖(Optional)
作用
Maven 的可选依赖属性
optional
用于标记某个依赖是否是可选的。默认行为:Maven 会传递所有依赖的依赖(传递性依赖),即如果项目 A 依赖项目 B,而项目 B 又依赖项目 C,则项目 A 会默认获取 B 和 C。
使用
optional
可以避免这种传递性。
场景
当某个依赖是额外的功能模块,而下游项目可能不需要它时。
避免引入无用的依赖,减少构建时间和冲突风险。
示例
项目 A 依赖项目 B,项目 B 依赖项目 C:
<dependency>
<groupId>org.example</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
</dependency>
项目 B 中声明 C 为可选依赖:
<dependency>
<groupId>org.example</groupId>
<artifactId>project-c</artifactId>
<version>1.0.0</version>
<optional>true</optional>
</dependency>
结果:项目 A 不会自动获取 C,除非手动添加。
3、Maven 中的依赖排除(Exclusions)
作用
排除传递性依赖中不需要的模块。
为什么需要?
防止依赖冲突(例如不同版本的库)。
删除多余的依赖以优化项目构建。
示例
项目 A 依赖项目 B,而项目 B 又依赖项目 C,但项目 A 不需要 C。
<dependency>
<groupId>org.example</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>org.example</groupId>
<artifactId>project-c</artifactId>
</exclusion>
</exclusions>
</dependency>
传递性依赖的层级示例
项目 A -> 项目 B -> 项目 C。
如果不需要项目 C,可通过
exclusions
将其排除,最终 A 只包含 B。
常见问题解决
依赖冲突:当传递性依赖中某个库的多个版本引入冲突时,排除旧版本并手动引入所需版本。
避免不必要的依赖:减少构建体积,避免不需要的模块。
Maven的继承
Maven 的继承机制允许项目的 POM 文件继承另一个 POM 文件中的配置,从而避免重复定义相同的配置。
1. 继承的特点
层级结构:Maven 的继承是树状结构,一个子项目只能继承一个父项目。
统一管理:父 POM 通常定义通用的依赖、插件、构建配置等,子 POM 自动继承。
减少重复:多个子项目可以共享父 POM 中的配置,提高复用性。
2. 父 POM 定义
父 POM 中定义通用配置,例如:
x
3. 子项目继承
子项目通过 <parent>
标签指定父 POM:
x
子项目继承父 POM 的依赖管理和插件配置。
可在子项目中覆盖或补充父 POM 的配置。
多模块机制用于将一个大项目拆分为多个模块,每个模块都是一个独立的 Maven 项目,但可以共享配置和依赖。
Maven的多模块
1. 多模块结构
多模块项目通常有一个父 POM 和多个子模块,目录结构如下:
project-root/
├── pom.xml # 父 POM
├── module-a/ # 子模块 A
│ └── pom.xml
├── module-b/ # 子模块 B
│ └── pom.xml
2. 父 POM(根 POM)
父 POM 除了继承机制的配置外,还需要声明模块:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging> <!-- 必须是 pom 类型 -->
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
</project>
3. 子模块的 POM
子模块 POM 需要指定父项目:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>module-a</artifactId>
</project>
4. 构建和依赖管理
构建:在根目录运行
mvn install
,会依次构建所有模块。
依赖管理:模块之间可以互相依赖:
<dependency>
<groupId>com.example</groupId>
<artifactId>module-a</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
5. 优势
模块化:每个模块负责单一功能,便于开发和维护。
共享配置:通过父 POM 统一管理版本和插件。
并行构建:Maven 可以并行构建多个模块,加快构建速度。
Maven测试和打包
在 IDEA 中,Maven 项目有多个生命周期,每个生命周期对应一个插件执行任务。常见的命令如下:
clean
:清理target
文件夹,解决缓存问题。validate
:验证项目的可用性。compile
:编译项目为.class
文件。install
:将项目安装到本地仓库,供其他项目作为依赖使用。verify
:依次执行validate
、compile
、package
等生命周期阶段。
每个命令执行完后,IDE 会显示 BUILD SUCCESS
,如果出现错误则会显示详细信息。
1. 测试命令
通过 test
命令,Maven 会自动运行 test
目录下的所有测试案例。测试类的名称需要以 Test
结尾(例如 MainTest
),测试方法必须标注 @Test
注解。示例如下:
public class MainTest {
@Test
public void test() {
System.out.println("我测你码");
}
}
2. 打包命令
使用 package
命令可以将项目打包成 JAR 文件,生成的 JAR 文件可以作为其他项目的依赖或可执行文件。执行 package
时,会先自动执行测试命令,确保项目没有问题。如果希望跳过测试,可以使用以下命令:
mvn package -Dmaven.test.skip=true
3. 打包带依赖的 JAR 文件
通常,打包后的 JAR 文件仅包含项目自己的类,而缺少所需的外部依赖。如果要将项目及其依赖一起打包,可以使用 maven-assembly-plugin
插件。插件配置如下:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.test.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
配置好后,重新执行 package
命令,最终会生成两个 JAR 文件:一个是普通的 JAR 文件,另一个是包含所有依赖的 JAR 文件。我们只需要执行以下命令即可运行:
java -jar your-project-jar-with-dependencies.jar