pom.xml

下面的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>cn.itbaima</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>

我们可以看到,Maven的配置文件是以project为根节点,而modelVersion定义了当前模型的版本,一般是4.0.0,我们不用去修改。
groupId、artifactId、version这三个元素合在一起,用于唯一区别每个项目,别人如果需要将我们编写的代码作为依赖,那么就必须通过这三个元素来定位我们的项目,我们称为一个项目的基本坐标,所有的项目一般都有自己的Maven坐标,因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了,无需再下载Jar文件,而是Maven自动帮助我们下载依赖并导入:

  • groupId 一般用于指定组名称,命名规则一般和包名一致,比如我们这里使用的是org.example,一个组下面可以有很多个项目。
  • artifactId 一般用于指定项目在当前组中的唯一名称,也就是说在组中用于区分于其他项目的标记。
  • version 代表项目版本,随着我们项目的开发和改进,版本号也会不断更新,就像LOL一样,每次赛季更新都会有一个大版本更新,我们的Maven项目也是这样,我们可以手动指定当前项目的版本号,其他人使用我们的项目作为依赖时,也可以根本版本号进行选择(这里的SNAPSHOT代表快照,一般表示这是一个处于开发中的项目,正式发布项目一般只带版本号)

properties中一般都是一些变量和选项的配置,我们这里指定了JDK的源代码和编译版本为17,同时下面的源代码编码格式为UTF-8,无需进行修改。

Maven依赖导入

现在我们尝试使用Maven来帮助我们快速导入依赖,我们需要导入之前的JDBC驱动依赖、JUnit依赖、Mybatis依赖、Lombok依赖,那么如何使用Maven来管理依赖呢?

我们可以创建一个dependencies节点:

<dependencies>
    //里面填写的就是所有的依赖
</dependencies>

那么现在就可以向节点中填写依赖了,那么我们如何知道每个依赖的坐标呢?我们可以在:Sonatype Central 进行查询,我们直接搜索Lombok即可,打开后可以看到已经给我们写出了依赖的坐标:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.36</version>
</dependency>

maven01
通过流程图我们得知,一个项目依赖一般是存储在中央仓库中,也有可能存储在一些其他的远程仓库(可以自行搭建私服)几乎所有的依赖都被放到了中央仓库中,因此,Maven可以直接从中央仓库中下载大部分的依赖(因此Maven第一次导入依赖是需要联网的,否则无法下载)远程仓库中下载之后 ,会暂时存储在本地仓库,我们会发现我们本地存在一个.m2文件夹,这就是Maven本地仓库文件夹,默认建立在C盘,如果你C盘空间不足,会出现问题。

在下次导入依赖时,如果Maven发现本地仓库中就已经存在某个依赖,那么就不会再去远程仓库下载了。

注意(可选): 因为中心仓库服务器位于国外,下载速度缓慢,可能在导入依赖时会出现卡顿等问题,我们需要使用国内的镜像仓库服务器来加速访问(镜像仓库与中心仓库自动同步所有依赖,访问速度更快)有两种方式配置:

  1. 可以配置IDEA自带的Maven插件远程仓库镜像地址,我们打开IDEA的安装目录,找到安装根目录/plugins/maven/lib/maven3/conf文件夹,找到settings.xml文件,打开编辑,找到mirros标签,添加以下内容:
<mirror>
  <id>aliyunmaven</id>
  <mirrorOf>central</mirrorOf>
  <name>阿里云公共仓库</name>
  <url>https://maven.aliyun.com/repository/public</url>
</mirror>
  1. 自行前往Maven官网并下载最新版的Maven安装,然后将IDEA的Maven配置为我们自行安装的位置(好处是IDEA更新后不需要重新配置)可以一直使用,镜像配置方式同第1步。

Maven依赖作用域

除了三个基本的属性用于定位坐标外,依赖还可以添加以下属性:

  • type:依赖的类型,对于项目坐标定义的packaging。大部分情况下,该元素不必声明,其默认值为jar
  • scope:依赖的范围(作用域,着重讲解)
  • optional:标记依赖是否可选
  • exclusions:用来排除传递性依赖(一个项目有可能依赖于其他项目,就像我们的项目,如果别人要用我们的项目作为依赖,那么就需要一起下载我们项目的依赖,如Lombok)
    我们着重来讲解一下scope属性,它决定了依赖的作用域范围:
  • compile :默认的依赖有效范围,如果在定义依赖关系的时候,没有明确指定依赖有效范围的话,则默认采用该依赖有效范围,此范围表示在编译、运行、测试时均有效。
  • provided :仅在编译、测试时有效,但是在运行时无效,也就是说,项目在运行时,不需要此依赖,比如我们上面的Lombok,我们只需要在编译阶段使用它,编译完成后,实际上已经转换为对应的代码了,因此Lombok不需要在项目运行时也存在。
  • runtime :在运行、测试时有效,但是在编译代码时无效。比如JDBC驱动就是典型的只需要运行时使用,因为JDBC驱动由数据库厂商开发,我们使用的始终是JDK中提供的接口,不需要直接使用特定驱动中的类或是方法,因此只需在运行时包含即可。
  • test :只在测试时有效,例如:JUnit框架,我们一般只会在测试阶段使用JUnit,而实际项目运行时,我们就用不到测试了,所以这个选项非常适合测试相关的框架。
    这里我们来测试一下JUnit,我们可以在网站上搜索JUnit的依赖,我们这里导入最新的JUnit5作为依赖:
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

我们所有的测试用例全部编写到Maven项目给我们划分的test目录下,位于此目录下的内容不会在最后被打包到项目中,只用作开发阶段测试使用:

public class MainTest {
    @Test
    public void test(){
        System.out.println("测试");
      	//Assert在JUnit5时名称发生了变化Assertions
        Assertions.assertArrayEquals(new int[]{1, 2, 3}, new int[]{1, 2});
    }
}

因此,一般仅用作测试的依赖如JUnit只保留在测试中即可,那么现在我们再来添加JDBC和Mybatis的依赖:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

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仓库中。
接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了,只需要填写和这边一样的坐标:

接着我们就可以在自己的项目中直接使用了:

注意,如果我们的旧项目中引入了一些其他的依赖,那么此依赖是会一起被传递的,比如这里我们添加了MyBatis的依赖到原项目中:
此时在引入此项目的其他项目中,此依赖也被一起传递:
也就是说,当我们的项目依赖于其他内容时,为了保证完整性,默认情况下会一并引入所有此项目包含的依赖项。
在某些情况下,可能我们并不希望某些依赖直接被项目连带引入,因此,当项目中的某些依赖不希望被使用此项目作为依赖的项目使用时,我们可以给依赖添加optional标签表示此依赖是可选的,默认在导入依赖时,不会导入可选的依赖:

<optional>true</optional>

比如Mybatis的POM文件中,就存在大量的可选依赖:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.30</version>
  <optional>true</optional>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.30</version>
  <optional>true</optional>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
  <optional>true</optional>
</dependency>

由于Mybatis要支持多种类型的日志,需要用到很多种不同的日志框架,因此需要导入这些依赖来做兼容,但是我们项目中并不一定会使用这些日志框架作为Mybatis的日志打印器,因此这些日志框架仅Mybatis内部做兼容需要导入使用,而我们可以选择不使用这些框架或是选择其中一个即可,也就是说我们导入Mybatis之后想用什么日志框架再自己加就可以了。
现在我们可以让使用此项目作为依赖的项目不使用可选依赖,但是如果别人的项目中没有将我们不希望的依赖作为可选依赖,这就导致我们还是会连带引入这些依赖,这个时候我们就可以通过排除依赖来防止添加不必要的依赖,只需添加exclusion标签即可:

<dependency>
    <groupId>com.test</groupId>
    <artifactId>TestMaven</artifactId>
    <version>1.1-SNAPSHOT</version>
    <exclusions> 
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
          	
        </exclusion>
    </exclusions>
</dependency>

此时我们通过这种方式手动排除了Test项目中包含的MyBatis依赖,这样项目中就不会包含此依赖了。