Maven基础


一、Maven简介

1.1基本介绍

  Maven官方文档:Maven官方文档
  Maven是一款为Java项目构建管理、依赖管理的工具,使用Maven可以自动化构建、测试、打包和发布项目,大大提高了开发效率和质量。常见Maven使用场景:

  • 项目中需要第三方库(依赖),如Druid连接池、MySQL数据库驱动和Jackson等,可将依赖的信息写到maven的配置文件中,之后maven会自动下载并复制这些依赖到项目中,并确保依赖版本正确无冲突和完整性。
  • maven可管理项目的编译、测试、打包、部署等构建过程,通过实现标准的构建生命周期,maven可确保每一个构建过程都遵循同样的规则和最佳实践。同样,maven的插件机制也使得开发者可对构建过程进行扩展和定制。

1.2maven的安装与配置

1.2.1安装maven

安装条件:

  • 需要本机已配置Java环境。
  • 本机应包含JAVA_HOME环境变量。
    在这里插入图片描述
      可在命令行中使用maven命令判断是否完成安装:
C:\Users\28591>mvn -v
Apache Maven 3.9.7 (8b094c9513efc1b9ce2d952b3b9c8eaedaf8cbf0)
Maven home: C:\Users\28591\maven\apache-maven-3.9.7
Java version: 22.0.1, vendor: Oracle Corporation, runtime: C:\Users\28591\JDK
Default locale: zh_CN, platform encoding: UTF-8
OS name: "windows 11", version: "10.0", arch: "amd64", family: "windows"

在解压文件后可得到maven有如下文件结构:
在这里插入图片描述

  • bin:maven运行脚本。
  • boot:plexus-classworlds类加载器框架。
  • conf:settings.xml配置文件。
  • lib:Maven运行时所需要的java类库。
  • LICENSE.txt、NOTICE.txt、README.txt:针对Maven版本,第三方软件等简要介绍。

1.2.2maven配置

  在完成maven安装后,需要修改maven/conf/setting.xml配置文件,来修改maven的一些默认配置,主要修改依赖本地缓存位置、maven下载镜像、maven选用编译项目的jdk版本。

  • 配置本地仓库(settings标签下):本地存储依赖的位置。
<!-- localRepository
 | The path to the local repository maven will use to store artifacts.
 |
 | Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
<localRepository>C:\Users\28591\maven\apache-maven-3.9.7\Maven Repository</localRepository>
  • 配置国内阿里镜像(mirrors标签下):Maven会默认指向一个国外的下载地址用于下载依赖,下载速度过慢。
  <mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>https://maven.aliyun.com/nexus/content/groups/public</url>
      <mirrorOf>central</mirrorOf>
  </mirrors>
  • 选用编译项目的jdk版本(profiles标签下):maven会根据选择的jdk版本构建项目,使得有些java新特性无法支持。
  <profiles>
    <profile>
      <!--添加jdk编译版本-->
      <id>jdk-22</id>
      <activation>
        <activeByDefault>true</activeByDefault>
        <jdk>22</jdk>
      </activation>
      <properties>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <maven.compiler.compilerVersion>22</maven.compiler.compilerVersion>
      </properties>
    </profile>
  </profiles>

3.idea配置本地maven
  idea工具默认使用自带的maven配置软件,需要修改配置才能使用本地配置的maven。
在这里插入图片描述

1.3Maven仓库

  Maven 在某个统一的位置存储所有项目的构件,这个统一的位置,我们就称之为仓库,即,仓库就是存放依赖和插件的地方。项目构建完成生成的构件,也可以安装或者部署到仓库中,供其他项目使用。Maven仓库可分为本地仓库与远程仓库,根据依赖坐标查找仓库顺序为:

  • 首先查看本地仓库,若本地仓库存在此构件,则直接使用。
  • 若本地仓库不存在此构件,Maven 就会去远程仓库查找,若发现所需的构件后,则下载到本地仓库使用。
  • 如果本地仓库和远程仓库都没有所需的构件,则 Maven 就会报错。

在这里插入图片描述

  本地仓库实际就是本地计算机上的一个目录,默认地址为C:%USER_HOME%.m2\repository,而远程仓库可分为中央仓库、私服仓库、其他公共仓库三类:

  • 中央仓库: Maven 社区提供的一种特殊的远程仓库,它包含了绝大多数流行的开源构件。在默认情况下,当本地仓库没有 Maven所需的构件时,会首先尝试从中央仓库下载。
  • 私服:一种特殊的远程仓库,它通常设立在局域网内,用来代理所有外部的远程仓库。它的好处是可以节省带宽,比外部的远程仓库更加稳定。
  • 公共仓库:除了中央仓库和私服外,还有很多其他公共仓库,例如 JBoss Maven 库,Java.net Maven 库等。

  maven的配置文件settings.xml中提供了<mirror>标签用于拦截依赖请求,并将它们指向预先配置好的镜像仓库地址,当Maven 向原始的远程仓库请求依赖时,Maven 会依次查找 settings.xml 中的镜像列表,根据<mirrorOf>标签指定的匹配规则,匹配成功时Maven 不再直接访问原始远程仓库,而是转向镜像仓库请求相同的内容。配置方式:

  • <mirror>:定义一个镜像,其中包含镜像仓库的唯一标识(id)、名称、URL 和<mirrorOf> 元素,用于指定该镜像是哪些远程仓库的镜像。
    • <mirrorOf>设置为*,则表示此镜像将代理所有远程仓库的请求。
    • 若设置为某个仓库ID,则仅代理与该ID匹配的远程仓库请求。
    • 也可以配置一组仓库ID,用逗号分隔,来代理多个特定仓库的请求。

例1:

<mirrors>
    <mirror>
        <id>mirrorId1</id>
        <mirrorOf>*</mirrorOf>
        <url>http://mirror1.example.com</url>
    </mirror>
    <mirror>
        <id>mirrorId2</id>
        <mirrorOf>*</mirrorOf>
        <url>http://mirror2.example.com</url>
    </mirror>
</mirrors>

此时Maven 会首先尝试 mirrorId1 镜像仓库,如果在该仓库中找不到依赖,它会继续尝试 mirrorId2 镜像仓库。通过这种方式,可以优化 Maven 的依赖解析过程,确保它优先使用最快或最可靠的镜像源。

例2:

<mirror> 
	<id>A仓库的id</id> 
	<name>xxx</name> 
	<url>A仓库的url</url> 
	<mirrorOf>B仓库的id</mirrorOf> 
</mirror>

表示原本通过仓库B下载的依赖会转为从仓库A下载。

例3:

  一般来说,镜像匹配顺序等于列表顺序,但当出现通配符时,以准确匹配为准。

<mirror>
    <id>huaweicloud</id>
    <mirrorOf>*</mirrorOf>
    <url>https://mirrors.huaweicloud.com/repository/maven/</url>
</mirror>
 
<mirror> 
	<id>alimaven</id> 
	<name>aliyun maven</name> 
	<url>http://central.maven.org/maven2</url> 
	<mirrorOf>central</mirrorOf> 
</mirror>

虽然huaweicloud使用通配符,但从中央仓库依赖时仍选择准确匹配的alimaven。

二、基于IDEA的Maven项目创建

2.1Maven工程的GAVP属性

  maven相对于之前的工程要多出一组GAVP属性,是GroupIdArtifactIdVersionPackaing等属性的缩写,其中前三个属性是必要的,并且在创建项目时指定,而P有默认值,通过配置文件也可对这些属性进行修改。这四个属性主要为每个项目在maven仓库中做一个标识,有了具体的标识,maven就可对项目进行管理和互相引用。GAVP属性遵循以下规则:

  • GroupId格式:com.公司名.业务线.子业务线,如com.alibaba.sourcing.multilang,最多有四级。
  • ArtifactId格式:产品线名-模块名。如tc-client、uic-api。
  • Version格式:主版本号.次版本号.修订号。如初始:1.0.0、修改bug:1.0.1、功能增强:1.1.1。
    • 主版本号:当做了不兼容API修改,或者增加了能改变产品方向的新功能。
    • 次版本号:当做了向下兼容的功能性新增(新增类、接口等)。
    • 修订号:修复bug,没有修改方法签名的功能加强,保持API兼容性。
        Packaing用于指示将项目打包为什么类型的文件,idea也可根据packaging的值来识别maven项目类型。
  • jar(默认值):普通java工程,打包为.jar文件。
  • war:Java的web工程,打包为.war文件。
  • pom:代表不会打包,用来做继承的父工程。

2.2创建Maven JavaSE项目

在这里插入图片描述
项目结构:
在这里插入图片描述

注意:

  • 在创建项目时并未指定Version,其被赋予默认值<version>1.0-SNAPSHOT</version>,之后可在配置文件中修改。
  • 名称组ID工件ID并不冲突,前者是当前项目在当前电脑文件夹中的命名,而后者是当项目打包存储在maven仓库中的命名。
  • 默认情况下,项目仍使用IDEA自带的未配置maven,故需手动进行修改:
    在这里插入图片描述

2.3创建Maven JavaEE项目

1.手动创建

  • 创建一个maven javase工程。
  • 手动补全web项目结构。

  在上文JavaSE工程的基础上补全web项目结构(必须严格按照以下结构创建文件才能被maven识别):
在这里插入图片描述
  web.xml常用模板:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
	version="4.0">

</web-app>

可在设置中将其设置为常用模板:
在这里插入图片描述

2.使用插件快速补全web项目
  安装插件JBLJavaToWeb,在项目名上右击进行转换即可:
在这里插入图片描述

2.4项目结构说明

2.4.1Java SE项目结构

  使用maven创建Java项目后会生成固定的项目结构(默认是JavaSE项目):
在这里插入图片描述

路径功能
src/main/java存放Java源代码
src.main/resources存放资源文件
src/test/java存放测试源文件
src/test/resources存放测试资源文件
target存放打包输出文件
target/classes存放编译输出文件,即字节码文件
target/test-classes存放测试源代码编译生成的字节码文件
surefire-reports存放Maven 运行测试用例生成的测试报告
helloMaven-1.0-SNAPSHOT.jarMaven 对项目进行打包生成的 jar 文件。

2.4.2Java EE项目结构

在这里插入图片描述

三、Maven项目构建

3.1构建与生命周期

  项目的构建包含以下过程:
在这里插入图片描述
项目构建是指将源代码、配置文件、资源文件等转化为能够运行或部署的应用程序或库的过程。事实上,平时编写的Java源代码(.java文件)需要被打包为可运行文件(.class文件)的过程,就是构建,而这一过程由开发工具(IDEA、ecplise,不同开发工具构建出的软件包结构并不同)自动完成了。常见的构建工具包括Maven、Gradle、Ant等,不同的构建工具得到的软件包结构也不相同。

3.2命令方式完成项目构建

  maven构建项目的过程对应着maven中的不同命令:

命令功能
mvn compile编译项目,生成target文件
mvn package打包项目,生成jar或war文件
mvn clean清理编译或打包后的项目结构
mvn install打包后上传到maven本地仓库
mvn deploy只打包,上传到maven私服仓库
mvn site生成站点
mvn test执行测试代码

3.2.1项目编译与清理

1.在maven中下载依赖Lombok并编写JavaBean
在这里插入图片描述
2.mvn compile
在这里插入图片描述

  • classes:java类编译出的字节码文件。

3.mvn clean
在这里插入图片描述

3.2.2项目测试

  导入junit单元测试依赖:

<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-api</artifactId>
   <version>5.10.2</version>
</dependency>

编写测试代码:

package org.example;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class MavenTest {
    @Test
    public void testAssert(){
        int a=10;
        int b=20;
        Assertions.assertEquals(a+b,20);
    }
}

在这里插入图片描述  使用mvn test执行测试代码:
在这里插入图片描述
注意,在Maven工程中,测试类的测试类名、测试方法名必须以test开头或结尾(大小写不区分),否则maven无法识别出测试方法、测试类(与@Test注解无关)。

3.2.3项目报告

  项目报告会保存当前项目测试的结果,这并不需要使用指令来实现,而是在项目测试后自动保存在surefire-reports目录下与测试类名同名的txt文件中。

-------------------------------------------------------------------------------
Test set: org.example.MavenTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.041 s -- in org.example.MavenTest

3.2.4项目打包

1.jar包
命名规则:ArtifactId-版本.jar
在这里插入图片描述
可见,打包过程中会将源程序、测试程序编译,并执行测试代码等功能。注意,打包得到的jar包中不会包含测试程序。

2.war包
  注意,可能会出现war包打包插件和jdk版本不匹配问题,需在pom.xml中添加:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.3.2</version>
        </plugin>
    </plugins>
</build>

3.2.5项目安装

  项目安装是指将jar包或war包安装到本地仓库中,只有将jar包或war包安装到本地仓库(一般只含有通过maven从远程仓库下载的、maven自身所用插件的jar包)中,当前项目才通过配置pom.xml文件从本地仓库中获取软件包并使用。
  将上文项目使用mvn install指令后,即可通过配置pom.xml文件的方式来获取相应的jar包并使用:

<dependency>
    <groupId>org.example</groupId>
    <artifactId>maven01</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

可在资源管理器中找到该jar包,路径为:本地仓库路径\org\example\maven01\1.0-SNAPSHOT

3.3构建插件、命令、生命周期命令之间的关系

  上文中执行package命令时也会自动执行compile命令,这种行为就是因为构建生命周期产生的,构建生命周期可理解为一组固定构建命令的有序集合,触发后面的命令时,会自动触发周期前的命令。主要的两个构建生命周期:

  • 清理周期:对编译生成的文件进行清理。
    • 包含命令:clean
  • 默认周期:包含真正构建时所需执行的所有步骤,是生命周期中最核心的部分。
    • 包含命令:compile->test->package->install->deploy

在这里插入图片描述

构建插件、命令、生命周期命令之间的关系:周期包含若干命令,命令又与若干插件对应,构建过程实质是使用周期命令构建,最终进行构建的是插件。

四、Maven依赖管理

在这里插入图片描述

4.1POM文件的编写

  POM(Project Object Model,项目对象模型)是 Maven 的基本组件,它是以 xml 文件的形式存放在项目的根目录下,名称为 pom.xml。POM文件将项目对象化,可在配置文件中定义了项目的基本信息,用于描述项目如何构建、声明项目依赖等。当 Maven 执行一个任务时,它会先查找当前项目的 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>
  <!--公司或组织的唯一标识,且配置生成的路径也是由此生成,如org.example,maven会将项目打包的jar包存放在本地路径:/org/example-->
  <groupId>org.example</groupId>
  <!--项目的唯一ID,一个groupId下可能有多个项目,通过artifactId进行区分-->
  <artifactId>maven01</artifactId>  
  <!--版本号-->
  <version>1.0-SNAPSHOT</version>  
  <packaging>jar</packaging>
  <properties>
    <maven.compiler.source>22</maven.compiler.source>
    <maven.compiler.target>22</maven.compiler.target>  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
  </properties>
  <dependencies>
  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.32</version>
      <scope>provided</scope>
  </dependency>
  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.10.2</version>
  </dependency>
  </dependencies>
</project>
  • groupIdartifactId:创建项目时指定,一般不会再修改。
  • version:构建过程中,项目部署时进行修改,修改规则见上文。
  • packaging:指定maven工程的打包方式。
  • dependecies:第三方依赖信息声明,是项目依赖信息的集合,其中每一个依赖都对应一个dependency标签。
  • dependency:对应一个依赖项(打为jar包的maven工程),需填写其基本的GAV属性。有以下方式获取jar包的相关信息:
    • maven提供了查询官网:maven官方仓库,即可查到相应的属性信息。
    • maven插件maven-search可从国内maven仓库中获取依赖,访问速度更块。
      在这里插入图片描述
  • <properties>:声明全局变量,在其他位置可通过${变量名}进行引用,如,对Jar包版本的统一管理:
    在这里插入图片描述
      无论 POM 文件中是否显示的声明,所有的 POM 均继承自一个父 POM,这个父 POM 被称为 Super POM。在pom的继承关系中,子pom可以覆盖父pom中的配置,按照这个规则,继承关系中的所有pom叠加到一起,就生成一个最终生效的pom。maven实际运行的过程中,执行构建操作就是按照这个最终的pom运行起来的。最终的pom也叫作有效pom翻译为effective POM,通过mvn help:effective-pom命令就可以查看项目的最终生成的pom(有效的pom),在该pom中会给出所有隐藏的标签信息。

4.2依赖范围

  可通过<dependency>下的scope标签来设置jar包的作用范围:编译环境、测试环境、运行环境(即最终的war包中是否可用,注意而非jar包,因为war包会包含程序运行所需的所有jar包,而jar包则由maven下载其依赖。运行环境是否可用是指依赖是否会被包装到应用程序当中)。
在这里插入图片描述
  此处的三种环境(classpath)可在项目结构中进行查看:
在这里插入图片描述

4.2.1compile

  编译依赖范围,是scope默认值,设置后的依赖在编译环境、测试环境、运行环境下均可用。
在这里插入图片描述
其中,junit-platform-commons-1.10.2.jaropentest4j-1.3.0.jarapiguardian-api-1.1.2.jar都是pom.xml中junit-jupiter-api所依赖的jar包。

4.2.2Test

  测试依赖范围,使用此依赖范围的maven依赖,只对测试环境有效,最为常见的junit依赖只在测试环境才生效(测试程序也不会被打包到war包中)。
在这里插入图片描述

4.3.3Provided

  已提供依赖范围,只对编译和测试环境有效,如servlet-api依赖对于编译、测试阶段是需要的,但是运行阶段,由于外部容器已经提供,故无需Maven重复引入该依赖。
在这里插入图片描述
tomcat服务器中已提供该jar包,故无需打包到war包中,并且需要注意服务器中所提供的servlet-api的版本。

4.4Maven工程依赖下载错误问题

在这里插入图片描述
常用解决方案:

  • 检查网络连接和Maven仓库服务器状态。
  • 确保依赖项的版本号与项目对应的版本号匹配,并检查POM文件中的依赖项是否正确,如junit4与junit5不仅要修改版本号,也要修改groupId、artifactId。
  • jar包在下载过程中可能会出现丢失(下载过程中网络断连)、下载错误等情况,此时需要清除本地Maven仓库缓存(lastUpdated文件),因为只要存在lastUpdated缓存文件,刷新也不会重新下载。需要根据依赖的GAV属性查找本地仓库,最终删除内部文件即可重新下载。

关于lastUpdated文件:
  .lastUpdated文件是 Maven 在下载依赖包时的中间文件。如:

slf4j-api-1.7.5.pom.lastUpdated
surefire-junit4-2.12.4.jar.lastUpdated

在下载完成后,.lastUpdated文件会被移除,成功下载的包文件将会出现。看到该文件可能有两种情况:

  • Maven正在下载该依赖
  • Maven上一次下载该依赖时发生了错误而中断:此时需要手动清理.lastUpdated文件(直接在本地仓库中把版本目录删除也行),否则.lastUpdated文件既不可用,又会导致maven不会重新下载。

4.5build工程构建配置

  项目构建是指将源代码、依赖库和资源文件等转换为可执行或可部署的应用程序的过程,包括编译源代码、链接依赖库、打包和部署等多个步骤。默认情况下,构建不需要额外配置,都有对应的默认值,也可在pom.xml中的<build>标签下进行配置。

<build>
    <!--设置打包名称-->
    <finalName>mavenProject</finalName>
    <!--设置要打包的资源位置-->
    <resources>
        <resource>
            <!--设置资源所在目录-->
            <directory>src/main/java/mapper</directory>
            <includes>
                <!--设置要打包的资源类型-->
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
    <plugins>
        <!--引入tomcat插件(本质仍是仓库中的jar包)-->
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.1</version>
            <!--设置tomcat相关配置-->
            <configuration>
                <port>8080</port>
                <path>/</path>
                <uriEncoding>UTF-8</uriEncoding>
                <server>tomcat7</server>
            </configuration>
        </plugin>
    </plugins>
</build>
  • <finalName>:默认打包名称为artifactId-版本号.jar/war,自定义名称时无需写上后缀。
  • <resources>:指定构建打包时,指定包含文件格式和排除文件。比如MyBatis中有时会将用于编写SQL语句的映射文件和Mapper接口都写在src/main/java下的某个包中,此时Maven就不会将其打包到jar/war包中,需要使用标签<resources>
  • <plugins>:可在<build>中引入插件,插件的本质仍是jar包,引入方式与普通依赖相同。在引入tomcat插件后即可直接使用tomcat,而无需进行配置。

4.6依赖传递

  Java项目之间可能存在相互依赖(引用)的关系,如,项目A依赖于项目B(A->B),项目B依赖于jar包C(B->C),即A包传递依赖于jar包C,则当项目A中需要导入于B的依赖时,Maven会自动将jar包C导入,这就是依赖的传递特性。传递依赖好处在于:

  • 减少重复依赖:当多个项目依赖于同一个库时,Maven可自动下载且只下载一次该库,这样可减少项目的构建时间和磁盘空间。
  • 自动管理依赖:Maven可自动管理依赖项,使用依赖传递,简化了依赖项的管理,使项目构建更加可靠和一致。
  • 保证依赖版本正确性:通过依赖传递而下载的依赖之间都不会存在版本兼容性问题。

例:
在这里插入图片描述

4.6.1依赖传递原则

传递的原则:在A依赖B、B依赖C的前提下,C能否传递依赖到A,取决于B依赖C时所使用的依赖范围以及配置:

  • B依赖C时使用compile范围:可以传递。
  • B依赖C时使用test或provided范围:不能传递,所以需要这样的jar包时,必须在配置文件中明确指明依赖才可以。

在这里插入图片描述

  • B依赖C,但若配置<optional>标签,则依赖不可传递:
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.22</version>
  <optional>true</optional>
</dependency>

在这里插入图片描述

4.6.2依赖传递冲突

  依赖传递终止包含:

  • 非compile范围进行依赖传递。
  • 使用optional配置终止传递。
  • 依赖传递冲突(传递的依赖已存在)。

前两者上文已指出,对于第三种的情况,当直接引用或间接引用相同的jar包时,一个项目就会出现相同的重复jar包,这就是依赖传递冲突,为避免出现重复依赖,需终止依赖的传递。如:
在这里插入图片描述
maven有自动解决依赖冲突的呢能力,会按照自己的原则进行重复依赖选择,同时也提供了手动解决冲突的方式(不推荐)。
  解决依赖冲突(如何选择重复依赖)的方式:

  • maven自动选择原则
    • 短路径优先原则(第一原则)
      在这里插入图片描述

在这里插入图片描述

- 依赖路径长度相同的情况下,则先声明的优先(第二原则)

在这里插入图片描述

在这里插入图片描述

  • 手动排除:

此时模块A需选择B传递的druid包或直接依赖的druid包,即发生依赖传递冲突。
依赖传递演示:需导入Jackson DatabindJackson CoreJackson Annotions三个依赖,而Jackson Databind(2.10.0版本)又依赖于Jackson CoreJackson Annotions,故只需导入Jackson Databind即可。
在这里插入图片描述

在这里插入图片描述

4.7依赖冲突

  依赖之间可能存在循环依赖的情况,如:
A − > B − > C − > A A->B->C->A A>B>C>A
此时称为依赖冲突。当发生重复依赖导入时,Maven会自动终止依赖传递,以解决依赖冲突问题。但当发生以下情况:
A − > B ( 1.0 ) C − > B ( 2.0 ) A->B(1.0)\\ C->B(2.0) A>B(1.0)C>B(2.0)
此时A、C依赖于B的不同版本,为避免重复导入依赖B,Maven在发生依赖冲突时遵循以下原则:

  • 短则优先:依赖引用路径长度短的优先导入,如 A − > C − > B ( 1.0 ) , F − > B ( 2.0 ) A->C->B(1.0),F->B(2.0) A>C>B(1.0)F>B(2.0),此时会导入依赖B(2.0)。
  • 上则优先:当依赖引用路径长度相同时,在<dependencies>中先声明的就优先导入,如 A − > B ( 1.0 ) , C − > B ( 2.0 ) A->B(1.0),C->B(2.0) A>B(1.0)C>B(2.0),若先声明A,则会导入B(1.0)而非B(2.0)。

例如:
依赖关系: A ( 1.1 ) − > B ( 1.1 ) − > C ( 1.1 ) F ( 2.2 ) − > B ( 2.2 ) p o m 声明顺序: F ( 2.2 ) 、 A ( 1.1 ) 依赖关系: A(1.1)->B(1.1)->C(1.1) F(2.2)->B(2.2) pom声明顺序:F(2.2)、A(1.1) 依赖关系:A(1.1)>B(1.1)>C(1.1)F(2.2)>B(2.2)pom声明顺序:F(2.2)A(1.1)
最后导入依赖为:F(2.2)、A(1.1)、B(2.2)。因为B包存在依赖冲突时,由于F(2.2)->B(2.2)较短,故优先导入B(2.2),并且由于发生依赖冲突,Maven不会导入后续的依赖,即C(1.1)不会被导入。

4.8手动排除依赖

  依赖传递过程中,可使用<dependencies>下的<exclusion>标签(依赖排除标签)来排除传递来的依赖,例:
在这里插入图片描述
也可在模块B的druid依赖下使用<optional>true<optional>来终止该以来的传递,但这也使得模块B无法传递依赖给别的模块,故更推荐使用<exclusions>

五、Maven工程继承与聚合

5.1Maven工程继承关系

  Maven继承是指在Maven的项目中,让一个项目从另一个项目中继承配置的机制,继承可让我们在多个项目中共享同一配置信息,使得父工程中可同一管理项目中的依赖信息,简化项目的管理和维护工作。建立继承关系的背景:

  • 对一个比较大型的项目进行了模块拆分。
  • 一个project下面,创建了多个module。
  • 每一个module都需要配置自己的依赖信息。

在这里插入图片描述
继承语法

<!--父工程-->
<groupId>org.atguigu.maven</groupId>  
<artifactId>mavenProject</artifactId>
<version>1.0-SNAPSHOT</version>
<!--当前工程作为父工程,它要管理子工程,所以打包方式为pom-->
<packaging>pom</packaging>

<!--子工程-->
<!--使用parent标签指定当前工程的父工程-->
<parent>
	<!--父工程的坐标-->
	<groupId>com.atguigu.maven</groupId>
	<artifactId>mavenProject</artifactId>
	<version>1.0-SNAPSHOT</version>
</parent>
<!--子工程的坐标,子工程坐标中的groupId和version需与父工程一致-->
<artifactId>mavenModule</artifactId>

案例:
在这里插入图片描述

5.2Maven父工程统一依赖管理

  子工程默认情况会直接继承父工程中的所有依赖及对应的scope范围:
在这里插入图片描述
事实上,在父工程中一般并不会使用<dependencies>标签,而是使用<dependencyManagement>(依赖管理)标签,此时子进程不会无条件继承父工程的依赖,而是手动选择需要继承的依赖。并且,在继承依赖时,只需指明groupIdartifactId即可:
在这里插入图片描述

5.3Maven工程聚合关系

  Maven聚合是指将多个项目组织到一个父级项目中,以便一起构建和管理。聚合可以更好地管理一组相关的子项目,同时简化它们的构建和部署过程。聚合的作用:

  • 管理多个子项目:通过聚合,可将多个子项目组合在一起,方便管理和维护。
  • 构架和发布一组相关的项目:通过聚合,可在一个命令中构建和发布多个相关的项目,简化了部署和维护工作。
  • 优化构建顺序:通过聚合,可对多个项目进行顺序控制,避免出现构建依赖混乱,导致构建失败的情况。
  • 统一管理依赖项:通过聚合,可在父项目中管理公共依赖和插件,避免重复定义。

聚合语法:父项目中含有子工程列表

<project>
	<groupId>org.example</groupId>
	<artifactId>mavenParent</artifactId>
	<version>1.0-SNAPSHOT</version>
	<!--当前工程作为父工程,它要管理子工程,所以打包方式为pom-->
	<packaging>pom</packaging>
	<modules>
		<!--此处为子工程的路径,而非工程名-->
	    <module>mavenSon_A</module>
	    <module>mavenSon_B</module>
	</modules>
</project>

六、Maven私服

6.1Maven私服简介

在这里插入图片描述
在这里插入图片描述
Maven私服的优势:
在这里插入图片描述
常见的Maven私服产品:

  • Apache的Archiva
  • JFrog的Artifactory
  • Sonatype的Nexus(最流行、使用最广泛)

6.2Nexus下载安装

  下载地址:Nexus下载地址。将下载 Nexus 安装包解压到本地磁盘,可获得 nexus-3.49.0-02 和 sonatype-work 2 个目录,
在这里插入图片描述

  • nexus-3.49.0-02:该目录中包含了 Nexus 3.x 运行所需要的文件,如启动脚本、依赖 jar 包等。
  • sonatype-work:该目录中包含了 Nexus 3.x 生成的配置文件、日志文件等。

  打开nexus-3.49.0-02/bin,其中nexus.exe是可运行的,但无法直接点击启动,需要通过命令将服务安装后再进行运行,并且nexus部分命令需要管理员的权限(win图标右键点击终端管理员):

Windows PowerShell
版权所有(C) Microsoft Corporation。保留所有权利。
安装最新的 PowerShell,了解新功能和改进!https://aka.ms/PSWindows
加载个人及系统配置文件用了 1171 毫秒。

(base) PS C:\Users\28591> cd C:\Users\28591\nexus\nexus-3.54.1-01\bin
(base) PS C:\Users\28591\nexus\nexus-3.54.1-01\bin> ./nexus /run

使用./nexus /run启动nexus,直到出现:
在这里插入图片描述
此时nexus启动成功。由于nexus本身是一个web工程,故访问方式等同于访问页面,首页地址为:http://localhost:8081,其中8081为默认端口号,访问页面为:
在这里插入图片描述

6.3Nexus初始配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  初始情况下nexus会提供七个仓库(四个maven仓库和三个nuget仓库),每个仓库都有以下属性:

  • type:仓库类型。
    • proxy:代理仓库用于代理远程公共仓库(实质保存了远程仓库的链接,通过代理来从远程仓库机进行下载),如 Maven 中央仓库、JBoss 远程仓库。在Server administration and configuration中可对远程仓库进行设置,如可将Remote storage换为阿里仓库。
    • hosted:宿主仓库,是Nexus 本地仓库,该仓库通常用来部署本地项目所产生的构件。 hosted 宿主仓库又分为:releases 和shapshots,分别表示依赖的版本的发行版、快照版。快照版依赖不能上传到发行版仓库,反之亦然。nexus做了限制(即后缀名带releases的jar包只能上传在releases 宿主仓库,shapshots同理)。
    • group:仓库组,用来聚合代理仓库和宿主仓库,为这些仓库提供统一的服务地址,以便 Maven 可以更加方便地获得这些仓库中的构件。
  • Format:仓库格式,有maven2与nuget两种。
  • Status:仓库的状态,只有在线状态才可被访问。
  • URL:仓库的路径。

6.4Nexus基本操作

6.4.1通过Nexus下载jar包

  在有了私服后,Maven的下载优先顺序为:中央仓库、私服仓库、本地仓库。可修改本地maven的配置文件setting.xml设置私服地址。
1.设置新的本地仓库地址:本地仓库为空,确保一定会去私服下载

<localRepository>C:\Users\28591\Desktop\res</localRepository>

在这里插入图片描述

2.将原先的阿里云镜像删除,写上nexus镜像:
在这里插入图片描述

<mirror>
  <id>nexus-mine</id>
  <mirrorOf>central</mirrorOf>
  <name>Nexus mine</name>
  <!--group仓库URL-->
  <url>http://localhost:8081/repository/maven-public/</url>
</mirror>

  若初始配置时设置了允许匿名访问,则此时已可正常访问仓库。但若并未设置,则需设置登录信息:

<server>
  <id>nexus-mine</id>
  <username>admin</username>
  <password>123456789</password>
</server>

注意,<server>标签内的id值必须与mirror中的id值相同。

3.项目构建
  使用命令,如mvn clean构建项目,由于本地仓库中不含对应jar包且私服中也不含有,故会先从中央仓库(nexus下的maven-central,下载速度过慢时可设置为阿里仓库地址)下载到私服(nexus下的maven-public),再由私服下载到本地仓库:
在这里插入图片描述

6.4.2将jar包部署到Nexus

  maven工程中配置:

<!--管理工程的部署位置--->
<distributionManagement>
    <snapshotRepository>
    	<!--id应与配置中server的id一致,因为部署时也需要进行用户登录-->
        <id>nexus-mine</id>
        <name>Nexus Snapshot</name>
        <!--需要部署的仓库地址-->
        <url>http://localhost:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
</distributionManagement>

使用生命周期中的deploy部署功能(mvn deploy):
在这里插入图片描述
在这里插入图片描述

6.4.3引用别人部署的jar包

  在maven中配置标签,指定下载源仓库的地址:

<repositories>
    <repository>
        <id>nexus-mine</id>
        <name>nexus-mine</name>
        <url>http://localhost:8081/repository/maven-snapshots/</url>
        <snapshots>
        	<!--能否使用快照版本依赖-->
            <enabled>true</enabled>
        </snapshots>
        <releases>
        	<!--能否使用正式版本依赖-->
            <enabled>true</enabled>
        </releases>
    </repository>
</repositories>

在这里插入图片描述

七、Maven综合案例

7.1项目需求和结构分析

在这里插入图片描述
项目结构:

  • 父工程micro-shop:统一管理依赖与插件,打包方式为pom。
  • 子工程user-service:用户服务子工程,负责处理用户相关的逻辑,如用户信息的管理、用户注册、登录等,打包方式为war。
    • spring-context 6.0.6
    • spring-core 6.0.6
    • spring-beans 6.0.6
    • common-service 6.0.6
  • 子工程order-service:订单服务子工程,负责处理订单相关的逻辑,如订单的创建、订单支付、退货、订单查看等,打包方式为war。
    • spring-context 6.0.6
    • spring-core 6.0.6
    • spring-beans 6.0.6
    • common-service 6.0.6
  • 子工程common-service:公共模块子工程,负责存储其他服务需要的通用工具类,其他服务依赖此模块,打包方式为jar。
    • commons-io 2.11.0
    • junit 5.9.2

7.2项目搭建和统一构建

  父工程micro-shop的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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>micro-shop</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

	<!--自动完成构建-->
	<modules>
    	<module>common-service</module>
    	<module>user-service</module>
    	<module>order-service</module>
	</modules>

    <properties>
        <spring.version>6.0.6</spring.version>
        <jackson.version>2.15.0</jackson.version>
        <commons.version>2.11.0</commons.version>
        <junit.version>5.9.2</junit.version>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--spring-context会传递依赖core、beans-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <!--jackson-databind会传递依赖core、annotations-->
            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jackson.version}}</version>
            </dependency>

            <!--commons-io-->
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>${commons.version}</version>
            </dependency>

            <!--junit-->
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--统一更新子工程打包插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>
        </plugins>
    </build>

</project>

父工程中统一管理依赖与插件,由于无需编写代码,可删除src目录。

  子工程common-service的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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>micro-shop</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>common-service</artifactId>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--配置spring-context,继承父工程版本,自动传递core、beans-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <!--配置jackson-databind,继承父工程版本,自动传递core、annotations-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <!--配置commons-io,继承父工程版本-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
        <!--配置junit,继承父工程版本-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

  子工程order-service的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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>micro-shop</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>order-service</artifactId>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>common-service</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <!--排除依赖项commons-io-->
                <exclusion>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                </exclusion>
                <!--排除依赖项jackson-->
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>

  子工程user-service的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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.example</groupId>
        <artifactId>micro-shop</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>user-service</artifactId>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--可使用公共模块common-service,包括其传递的依赖-->
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>common-service</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <!--排除依赖项commons-io-->
                <exclusion>
                    <groupId>commons-io</groupId>
                    <artifactId>commons-io</artifactId>
                </exclusion>
                <!--排除依赖项jackson-->
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>

此时通过公共子模块的传递,另外两个子模块也可使用相应的依赖:
在这里插入图片描述

  • 7
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值