maven 轻简知识

0 阅读6分钟

 

Maven 的介绍

Maven 是 Java 项目管理和构建的工具,它可以:

  • 定义项目结构
  • 管理项目依赖
  • 使用统一的方式进行自动化构建

是 Java 项目不可缺少的工具。

标准化的项目结构有助于程序的复现

不同的开发工具所创建的项目结构是不同的,而使用 Mavem 统一了项目结构,能增强项目的可阅读性,以及降低项目入手的门槛

规整的项目依赖好过复杂的 jar 包导入

Maven 工具会帮我们管理所有的 jar 包

传统的、不使用 Maven 的项目

  • jar 包与项目强绑定,必须要放置在项目文件夹中,如果项目 jar 包很多的情况下,占用磁盘空间会非常大
  • 团队协作开发时,每一个开发人员都需要下载对应的 jar 包文件
  • 传输项目时间长(因为项目大)

Maven 引入了“仓库”的概念

  • 仓库中放置了所有的 jar 包,需要的 jar 包会以依赖的方式从网络上下载并导入程序
  • 团队协作开发时,只需要将代码传输即可,jar 包会被 Maven 以依赖的形式自动导入

自动化的构建流程减少不必要的额外操作

Maven 提供了一套标准化的构建流程,它封装了一系列功能,对外暴露接口以供调用,那些复杂且无太大意义的过程被它隐藏了

Maven in 5 Minutes – Maven

编辑

Maven 的下载和安装

Maven 下载

Maven 官网: Download Apache Maven – Maven

编辑

系统 Maven 环境配置

环境的配置和 JDK 环境配置是一样的了,自行进行配置即可

编辑

Maven 基本配置

Maven 安装完成后在 apache-maven*/conf/settings.xml 文件中配置对应的基本信息。

当你第一次执行 mvn 相关的命令时,Maven 会自动在家目录中创建 .m2 文件夹,里面会放置全局的配置

接下来的基本配置可以在 .m2/settings.xml 中进行配置

Maven Jar 包安装路径配置

在下方可以增加 jar 包安装路径相关的配置,默认是放置在 .m2 文件夹中

编辑

Maven 仓库配置

在文件中可以增加中央仓库的配置,当依赖查找时会自上而下查找仓库中是否有对应的依赖

编辑

Maven 脚手架结构

使用 Maven 构造工具创建项目

如下图所示,可以使用构造工具创建对应的项目

编辑

脚手架内容结构

Maven 是基于约定的方式进行项目构建和管理的,比如下图中基础的脚手架结构,创建后会产生多个文件。(其中 .idea 和 .gitignore 分别是 IDEA 和 Git 自动生成的文件)

编辑

Maven 提供的自动打包工具

在 IDEA 的右侧菜单栏中可以使用 maven 自动打包工具,其中所有的操作都是顺序执行的,比如要使用 package 则前面的所有过程会被自动执行一遍

编辑

Maven 项目中 pom.xml 配置信息

<?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">
    <!-- maven 版本相关信息 -->
    <modelVersion>4.0.0</modelVersion>

    <!--
    设置打包方式,可以打成以下 3 中包的形式
     * jar: 依赖注入的需求,如果使用 war 则无法作为依赖注入其他项目(默认打包方式)
     * war: Tomcat 运行 Web 项目需要使用 war 包的形式
     * pom: 若是多模块项目,父模块不进行打包则使用 pom
     -->
    <packaging>jar</packaging>

    <!-- 坐标信息:可以通过下面三个变量确定 jar 包在仓库中的位置 -->
    <!-- groupId 一般使用域名反写 如: com.baidu -->
    <groupId>com.sereneDream</groupId>
    <!-- artifacId 一般使用项目名称 如: mavenTest -->
    <artifactId>mavenTest</artifactId>
    <!-- 为当前模块/项目的版本 -->
    <version>1.0-SNAPSHOT</version>

    <!-- 属性、变量可以在这里声明,随后在下方的依赖中直接引用。方便管理依赖版本 -->
    <properties>
        <!-- 当前项目的 JDK 版本 -->
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <!-- 当前项目的编码形式 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- 同样的,可以创造变量,比如我拥有一个 hutool 依赖,我可以在 properties 中声明变量,并在下面使用 -->
        <cn.hutool.version>5.8.37</cn.hutool.version><!-- 内容对应与 47 行的 hutool 依赖的版本 -->
    </properties>

    <!--
    依赖和 jar 包的区别:
     * 一个依赖中可能包含多个 jar 包
     * 依赖可以说是 maven 的专业名词
    所以在 Maven 项目中都是说:“引入一个‘依赖’”
    -->
    <!--
    dependencies 标明可以引入多个依赖
     - maven 在使用时,会现在本地仓库中查找依赖信息,
        如果本地仓库中没有对应的依赖信息,则回去远程仓库中查找
     - 在刚开始使用时,本地是没有对应的依赖信息缓存的,
        所以需要去依赖仓库直接获取对应的依赖信息
    依赖仓库地址: https://mvnrepository.com/
    -->
    <dependencies>
        <!-- 使用 <dependency> 标签的方式引入依赖 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${cn.hutool.version}</version><!-- 对应了 25 行的变量 -->
            <!-- 内容可替换为 <version>5.8.37</version> -->

            <!--
            依赖范围: 这个依赖在项目进行哪一项操作时会被使用,哪一项操作不会被使用
            范围种类(依赖能够在哪里使用/出现):
             * 编译(main/java)
             * 测试(main/test)
             * 运行/打包(能够出现在包内的依赖)

            依赖范围                范围种类                 示例依赖
            compile      编译✔️    测试✔️    打包✔️        默认依赖范围
            provided     编译✔️    测试✔️    打包✖️        servlet 这类 tomcat 服务器中已经依赖的 jar 包
            runtime      编译✖️    测试✔️    打包✔️        数据库驱动 这类使用反射获取的 jar 包
            test         编译✖️    测试✔️    打包✖️        junit 测试相关的依赖
            system       编译✔️    测试✔️    打包✖️        不会依赖仓库中的 jar 包,而是使用本地仓库中的 jar 包,
                                                          通常会与 <systemPath>本地仓库 jar 包地址</systemPath> 一起使用
            -->
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

依赖传递

简单而言就是如果你依赖了一个 jar 包中存在另一个你需要依赖的 jar 包,则视为你已依赖改 jar 包

比如:A 项目依赖了 B 项目, B 项目依赖了 hutool

根据依赖传递的特性,A 项目也会存在 hutool 依赖

当然,父项目也可以选择不去向子项目传递对应的依赖,可以使用 true 阻止依赖传递

<?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>

    <packaging>jar</packaging>

    <groupId>com.sereneDream</groupId>
    <artifactId>mavenTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cn.hutool.version>5.8.40</cn.hutool.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${cn.hutool.version}</version>
            <!-- 当父模块设置 optional 为 true 时,标明这个依赖不进行传递 -->
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

依赖的排除和覆盖

如果父模块不允许修改的情况下,子模块也可以通过 exclusion 标签对父模块的部分依赖进行忽略

<?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>

    <packaging>jar</packaging>

    <groupId>com.sereneDream</groupId>
    <artifactId>mavenTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <cn.hutool.version>5.8.40</cn.hutool.version>
        <spring-boot-starter-web.version>2.7.0</spring-boot-starter-web.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${cn.hutool.version}</version>
        </dependency>

        <!--
        这里我使用 spring-boot-starter-web 依赖进行 <依赖的排除和覆盖> 的示例,
        这个依赖会传递引入:
         - spring-webmvc(Spring MVC 框架)
         - spring-boot-starter-tomcat(内嵌 Tomcat 服务器)
         - spring-boot-starter-json(JSON 处理)
         - spring-boot-starter(Spring Boot 核心)
         - spring-core(Spring 核心)
         - ... 总共约 10-15 个依赖

        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot-starter-web.version}</version>
            <!--
            在 spring-boot-starter-web 依赖中,
             我们如果不想要使用其传递引入的依赖,可以使用 exclusions 标签对依赖进行排除
              同样的,一个 exclusions 中包含多个 exclusion
              -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-webmvc</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- 如果仅仅只是版本不符合项目所需,也可以使用覆盖的方式去覆盖父依赖引入的依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <version>4.0.2</version>
        </dependency>
    </dependencies>

</project>

Maven 聚合项目

一个 Maven 项目可以多模块,也就是聚合项目,如下图(mavenTest 的打包要设置为 pom)

编辑

在父模块中需要标明所有的子模块信息,这样子,当父模块点击打包时会同时将子模块的项目进行打包

如下图,我父模块仅仅声明了 a 为子模块,打包后,仅仅只有 a 模块进行了打包,b 模块没有任何活动

编辑

Maven 继承

在聚合的同时,子模块可以继承与父模块的依赖,即需要在子模块中添加父模块信息,如下图

父模块中引入了 hutool 依赖,子模块 a 开启了依赖,并标明了父模块信息,子模块 b 反之,从右侧的模块依赖信息可知:a 已经成功依赖 hutool,而 b 没有任何依赖

编辑