Maven 笔记

18

Maven

之前使用过很多次maven,但是一直没有系统的学习过,一些小项目还可以应付过去,但是一旦项目模块过多,需要配置构建过程时,真抓瞎了,发现自己对maven了解太少。

参考文档:代码重工 (gitee.io)

mvn命令

常用命令

archetype
可以通过maven来构建一个项目,不过一般情况下,我们使用idea来生成一个springboot或者java应用程序,idea自动帮我们做了。

  • mvn archetype:generate:生成一个maven项目

clean
该命令用来删除target目录,target目录中包含了编译生成的文件

  • mvn clean:删除target目录

compile
用该命令来编译项目

  • mvn compile:编译项目

test
执行项目中的单元测试

  • mvn test:该命令会自动帮我们执行项目中所有的单元测试类,并生成统计报告

package
将当前项目按配置方式(在packaging标签进行配置)进行打包

  • mvn package:打包当前项目

install
将当前项目打包并安装到本地仓库

  • mvn install:安装到本地仓库中
  • mvn install -Dmaven.test.skip=true:安装到本地仓库时,跳过测试

dependency
列出当前工程所依赖的jar包

  • mvn dependency:list:列出当前工程依赖的所有jar包
  • mvn dependency:tree:以树的形式列出当前工程依赖的所有jar包

test-compile
只对test文件进行编译

  • mvn test-compile:编译test文件

IDEA中三种执行命令的方式

  1. 通过maven插件直接点击lifecircle中的选项
  2. 通过idea中maven插件,点击执行命令窗口,在窗口中输入命令来执行
  3. 通过终端来执行命令

POM文件配置

项目结构

通过maven管理依赖的项目结构需要符合以下约定:

  • 项目根目录
    • src
      • main
        • 包名
      • test
        • 包名

依赖配置

依赖配置如下所示:

<dependency>
	<groupId></groupId>
	<artifactId></artifactId>
	<version></version>
	<scope></scope>
	<exclusions>
		<!--排除依赖-->
		<exclusion>
			<artifactId></artifactId>
			<groupId></groupId>
		</exclusion>
	</exclusions>
</dependency>

依赖的范围

通过scope标签进行配置
option

  • compile:只在编译期间有效,可以在main和test中导入,并且会将依赖进行打包。
  • test:只能在test下导入,不参与打包。
  • system:此范围与 provided 类似,只是您必须提供显式包含它的 JAR。工件始终可用,不会在存储库中查找。指定路径进行导入。
  • runtime:只在运行时有效,开发过程中无效。例如jdbc,开发过程中只需要知道接口进行,不需要知道具体实现,具体实现可以通过SPI在运行时导入。
  • provided:在开发过程中需要用到的“服务器上的jar包”通常以provided范围依赖进来。比如servlet-api、jsp-api。而这个范围的jar包之所以不参与部署、不放进war包,就是避免和服务器上已有的同类jar包产生冲突,同时减轻服务器的负担。
  • import:此范围仅在部分中 pom 类型的依赖项上受支持。它指示依赖项将替换为指定 POM 部分中的有效依赖项列表。由于它们被替换,因此具有导入范围的依赖项实际上并不参与限制依赖项的传递性。从父依赖中导入依赖列表。

依赖配置补充

依赖范围
import范围

因为maven是单继承的,也就是一个pom文件只能继承一个父pom,但有时我们又希望引入另一个pom中的依赖管理,此时可以用import标签。

使用限制

  • 只能用在dependencyManagement标签中
  • 依赖类型必须为pom
system范围

使用该标签可以引入本地磁盘上的jar包,需要通过systemPath标签指定jar包路径。
很明显,这样引入依赖完全不具有可移植性,所以不推荐使用,如果想保证jar包私有,可以自建maven仓库,而不是使用system标签。

runtime范围

程序编写和编译时不需要,运行时需要引入的包。一些专门的SPI依赖可以设置该范围,jdbc的具体实现依赖包也可以。

可选依赖optional

在依赖中可以配置optional标签,表示该依赖是可选的,可有可无,不保证一定会用到。

版本仲裁

如果当前工程中,它所依赖的其他工程中依赖了多个版本的jar包,那么对于当前工程来说,就必须选一个出来,这被称为版本仲裁,仲裁机制如下:

  1. 最短路径优先
  2. 路径相同最先声明者优先

依赖的传递性

compile范围的依赖具有传递性,test和provided范围的依赖不具有传递性。

排除依赖——解决jar包冲突

A依赖B、C,B依赖于D-0.1,C依赖于D-0.5,则如果A通过依赖的传递性可以导入D,但是会发生版本冲突,此时需要在A中导入B、C依赖的地方排除一个D。假如排除了B中的D-0.1,则在B中仍然使用D-0.1,在A中可以使用D-0.5,也就是在A中排除D,对应B来说是没有影响的。具体看下图,图表述的更清晰。

maven-依赖-排除依赖.png

依赖的继承

对于大型项目来说,模块比较多,它们都会包含相同的一些依赖,我们可以将这些共同依赖抽取出来,放到父工程中统一管理,具体来说就是管理依赖版本信息,从而实现一处修改,处处生效的效果。

通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的jar包,又能够将以往的经验沉淀下来,节约时间和精力。

对于一个企业来说,各种框架之间的依赖关系属于一个公司技术的沉淀,避免了重复造轮子和依赖冲突等问题。我们在新开一个项目时,除了应该采用成熟的框架之外,选择框架之间兼容的版本非常重要,避免项目后期各种难以发现的依赖冲突问题。

父工程

只有打包方式为pom的工程才是父工程,它里面不能有具体的实现。父工程可以通过mvn archetype:generate命令来创建,然后删除src目录、修改打包方式为pom、删除依赖包等。

父工程中有modules标签列出了它所包含的子工程。

管理依赖版本
管理依赖版本主要使用了properties标签,然后在dependencyManagement标签中使用这里配置的版本,示例如下:

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<springboot.version>2.6.7</springboot.version>
	<hutools.version>3.4.0</hutools.version>
	<junit.version>4.12</junit.version>
</properties>

管理依赖信息
管理依赖信息主要使用了dependencyManagement标签,示例如下:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
</dependencyManagement>

通过上面的配置后,可以直接在子工程中使用如下方式配置:

<dependencies>
    <dependency>
      <artifactId>junit</artifactId>
      <groupId>junit</groupId>
    </dependency>
</dependencies>

因为在父工程中已经对junit依赖包进行了管理,故此处可以省略其他信息,只需要指定groupid和artifactId即可。

子工程(模块工程)
在父工程的目录中运行mvn archetype:generate命令,maven会自动建立父子工程之间的联系(增加配置项)。

子工程中的parent标签指定了它的父工程的信息。

聚合

聚合的意义在于将整个工程进行统一管理,并且由maven来管理各模块之间的依赖关系,在打包时,maven会自动进行整体打包,不需要我们一个个去打包。

聚合其实就是将项目模块化,每个模块都是一个微服务,模块是子项目。在根项目下通过modules标签来配置模块。

mvn archetype:generate:通过这个命令生成的模块,maven会自动在父项目中进行配置
idea:通过idea添加的模块,idea也会自动进行配置
第三方:第三方引入的模块,需要自己手动在modules标签添加配置,并在第三方模块中对parent标签进行配置

循环依赖问题
这里需要注意的一点是循环依赖问题,当maven在打包时遇到循环依赖问题会报错。

生命周期

生命周期的类型

maven主要有三个生命周期,分别是Clean、Site、Default。三个生命周期之间是独立的,所以如果要对项目进行重新打包或者安装,需要的命令是mvn clean package。因为Clean和Default生命周期之间独立。

  • Clean:主要做清理工作,时间节点有pre-clean、clean、post-clean
  • Site:生成站点,一般不使用,时间节点有pre-site、site、post-site、deploy-site。
  • Default:主要的构建过程,时间节点如下所示,主要的节点已加粗。执行后面的节点,会将前面的也执行到,比如执行mvn deploy,则前面所有的节点都会被执行。
    • validate
    • generate-sources
    • process-sources
    • generate-resources
    • process-resources:复制并处理资源文件至目标目录,准备打包
    • compile:编译项目
    • process-classes
    • generate-test-sources
    • process-test-resources
    • generate-test-resources
    • process-test-resources
    • test-compile:编译测试文件
    • prepare-package
    • package:接受编译好的代码,打包成可发布的格式,如JAR。
    • pre-integration-test
    • integration-test
    • post-integration-test
    • verify
    • install:将包安装到本地仓库
    • deploy:将包部署到远程仓库,DevOps

插件和目标

插件

maven核心程序主要是做宏观调度,不负责具体的实现过程,具体的处理过程由maven插件来实现。比如编译是由maven-compiler-plugin-version.jar来完成的。

目标

一个插件可以对应实现多个目标,每一个目标都和生命周期中的一个节点一一对应。比如maven-compiler-plugin-version.jar实现了compile到test-compile之间的目标。

搭建Maven仓库

服务器配置

这里我们使用 Docker 容器,利用nexus来完成。

  • 拉取镜像:docker pull sonatype/nexus3
  • 运行镜像:docker run -d -p 8081:8081 --name nexus sonatype/nexus3
  • 可以通过浏览器查看仓库,地址为:ip:port,用户名为admin,密码保存在admin.password文件里面,可以通过find / -name admin.password命令找到文件路径,然后通过cat path/admin.password来查看密码。

客户端配置

通过 maven 的 settings.xml 文件来配置,添加如下内容。

<mirrors>
    <mirror>
    <id>mirror_id</id>
    <mirrorOf>*</mirrorOf>
    <name>mirror_name</name>
    <url>http://ip:port/repository/maven-public/</url>
</mirror>

如果要访问仓库中的私有内容,还需添加如下配置(密码或密钥,二选一)。

<servers>
    <server>
      <id>mirror_id</id>
      <privateKey>/path/to/private/key</privateKey>
      <passphrase>optional; leave empty if not used.</passphrase>
    </server>
    <server>
      <id>mirror_id</id>
      <username>repouser</username>
      <password>repopwd</password>
    </server>
</servers

如果需要使用仓库中的snapshot版本的jar包,则还需在 settings.xml 中插入如下内容:

<profiles>
    <profile>
        <id>profile_id</id>
        <repositories>
            <repository>
            <id>mirror_id</id>
            <url>http://ip:port/repository/maven-public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
      </repositories>
    </profile>
</profiles>

<activeProfiles>
    <activeProfile>profile_id</activeProfile>
</activeProfiles>

使用mvn deploy发布到远程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">
    <modelVersion>4.0.0</modelVersion>
    <distributionManagement>
        <repository>
            <id>repo</id>
            <url>http://ip:port/repository/maven-releases/</url>
        </repository>
        <snapshotRepository>
            <id>repo</id>
            <url>http://ip:port/repository/maven-snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

如果仓库需要密码才能进行推送,那么上面的 distributionManagement.repository.id 和 distributionManagement.snapshotRepository.id 需要和 settings.xml 文件中的 servers.server.id 对应。

相关问题

SNAPSHOT版本发布之后名称不对?依赖拉取不到?

snapshot版本上传到 maven 仓库之后,在 1.0-SNAPSHOT 文件夹下,默认保存的文件夹名是以时间戳命名的,这是正常的情况。客户端进行拉取snapshot版本包的时候,仓库默认返回最新版,并命名为 {project_name}.1.0-SNAPSHOT。

SpringCloud 微服务

SpringBoot项目打包插件
可以以SpringBoot微服务形式直接运行的jar包必须包含:

  • 当前微服务本身代码
  • 当前微服务所以来的jar包
  • 内置Tomcat容器
  • 可以通过java -jar方式直接运行的相关配置
    spring-boot-maven-plugin插件可以自动完成上述过程。可以通过下面的方式引入
<build>
	<plugins>
	<plugin>  
	    <groupId>org.springframework.boot</groupId>  
	    <artifactId>spring-boot-maven-plugin</artifactId>  
	</plugin>
	</plugins>
</build>

打包命令为:

mvn clean package spring-boot:repackage -Dmaven.test.skip=true

深入Maven

Maven四层结构

平时我们使用和配置的POM大致是由四个层次组成的:

  • 超级POM:所有POM默认继承,只是有直接和间接之分。该POM中配置的都是约定值。
  • 父POM:这一层可能没有,可能有一层,也可能有很多层。
  • 子POM:显式继承自父POM,我们最多关注和使用的一层。在父子POM中可以对默认值进行覆盖。
  • 有效POM:隐含的一层,实际上真正生效的一层。通过对有父子关系的POM计算后得到最终的生效的POM配置。

有效POM

  • mvn help:effective-pom:该命令将打印出最终生效的POM。
  • mvn help:evaluate:通过交互方式查看最终生效的properties(在POM文件中配置的)值。该命令也可等同于System.getProperty()
属性表达式

在POM文件中可以通过${}来获取属性值,这些属性值包括:

  • pom.xml文件中配置或继承的properties中的值。例如${junit.version}
  • 可以通过System.getProperty获取的系统变量。例如${user.dir}
  • 系统环境变量,需要加前缀env.来获取。例如${env.JAVA_HOME}
  • 项目配置信息,需要加前缀project.来读取。例如${project.groupId}
  • 在maven的settings.xml中配置的属性值,需要加前缀settings.来读取。例如${settings.localRepository}

在上面的例子中,如果值为列表,例如${project.modules},那么可以通过${project.modules[0]}来访问第一个值。

用途

  1. 可以在pom文件中使用
  2. 资源过滤功能:在非maven配置文件中引用属性,由Maven在处理资源时将属性表达式替换为属性值

build标签

一般情况下,maven超级pom中已经帮我们配置了一些默认的build参数,但是如果我们需要对构建过程进行定制,那么就需要自己编写build标签了。

build标签组成

build标签主要由三部分组成,分别是定义约定的目录结构、备用插件管理和生命周期插件。

定义约定的目录结构
  • sourceDirectory:主体源程序存放目录
  • outputDirectory:主体源程序编译结果输出目录
  • resources:主体资源文件存放目录
  • directory:构建结果输出目录
  • ...
备用插件管理

pluginManagement标签存放着几个极少用到的插件,该标签的功能类似于dependencyManagement,在pluginManagement中配置了plugin的详细信息后,在子工程中可以直接引入,无需指定版本号,可以在父工程中对插件进行统一管理。

生命周期插件

plugins标签存放的是默认生命周期中实际会用到的插件,这些插件都是些常用的,比如maven-compiler-plugin插件。配置到plugins中的插件会自动绑定到maven的生命周期中,当我们执行对应目标后,该插件也会在特定时间点被调用。
让我们来看看plugin标签的结构:

<plugin>
	<artifactId>maven-compiler-plugin</artifactId>
    <version>3.10.1</version>
    <executions>
	    <execution>
	    <!-- 指定唯一标识 -->
        <id>default-compile</id>
        <!-- 关联的生命周期阶段 -->
        <phase>compile</phase>
        <goals>
	        <!-- 关联指定生命周期的目标,可以配置多个 -->
	        <goal>compile</goal>
        </goals>
    </execution>
	<execution>
        <id>default-testCompile</id>
        <phase>test-compile</phase>
        <goals>
            <goal>testCompile</goal>
        </goals>
        </execution>
    </executions>
</plugin>

另外还可以在execution.configuration标签下对目标的执行过程进行配置。这部分配置是与插件相关的。

典型应用:指定编译的JDK版本

对编译阶段进行针对性配置,配置如下

<plugin>
	<artifactId>maven-compiler-plugin</artifactId>
    <version>3.10.1</version>
    <executions>
	    <execution>
	    <!-- 指定唯一标识 -->
        <id>default-compile</id>
        <!-- 关联的生命周期阶段 -->
        <phase>compile</phase>
        <goals>
	        <!-- 关联指定生命周期的目标,可以配置多个 -->
	        <goal>compile</goal>
        </goals>
    </execution>
	<execution>
        <id>default-testCompile</id>
        <phase>test-compile</phase>
        <goals>
            <goal>testCompile</goal>
        </goals>
        </execution>
    </executions>
    <configuration>
	    <!-- 源码的jdk版本 -->
	    <source>1.8</source>
	    <!-- 编译后class文件版本 -->
	    <target>1.8</target>
	    <encoding>UTF-8</encoding>
	</configuration>
</plugin>

一般我们不通过上面的方式对JDK进行配置,而是采用properties的方式。示例如下:

<properties>
	<maven.compiler.source>1.8</maven.compiler.source>
	<maven.compiler.target>1.8</maven.compiler.target>
<properties>

maven-compiler-plugin插件会自动读取这两个属性值进行配置。

两种配置方式

  • 通过settings.xml文件中的profile标签进行配置,如果项目被放到其他地方,就有可能发生问题。
  • 通过pom.xml进行配置后

典型应用:SpringBoot定制化打包

通过引入spring-boot-maven-plugin插件,该插件由Spring提供,用来改变maven默认的构建行为。使用maven自带的构建插件打包后无法通过java -jar xxx.jar命令来启动,对于SpringBoot项目来说,可以引入该插件,然后执行repackage目标即可,该插件会将执行SpringBoot项目所需的资源全部打包进jar包中,并且会对MANIFEST文件进行配置。

打包命令mvn clean compile spring-boot:repackage

插件配置如下:

<plugin>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-maven-plugin</artifactId>  
    <version>2.5.5</version>
</plugin>

典型应用:Mybatis逆向工程

Mybatis逆向工程就是通过数据库中的表文件生成符合我们配置信息的java代码(包含Entity、Mapper类、Mapper.xml文件等)。

参考资源地址:MyBatis逆向工程generator插件配置及使用 - oneMoe - 博客园 (cnblogs.com)

Mybatis分三步,分别是:

  1. 添加依赖和插件配置(配置mybatis-generator-maven-plugin插件)
  2. 创建generatorConfig.xml文件
  3. 在IDEA侧边栏点击使用插件生成,或者使用命令mvn clean mybatis-generator:generate

profile

可以在profile针对不同环境进行配置,并且可以设置在哪种匹配的环境下激活。可以针对开发、测试、生产环境做不同的配置。

<profiles>  
    <profile>  
	    <!-- 唯一id -->
        <id>disable-javadoc-doclint</id>
        <!-- 配置激活方式 -->
        <activation>
	        <!-- jdk版本大于等于1.8时激活 -->     
	        <jdk>[1.8,)</jdk>  
        </activation>
        <!-- 当前profile被激活时生效的配置信息 -->
        <properties>            
	        <javadoc.opts>-Xdoclint:none</javadoc.opts>  
        </properties>  
    </profile>  
</profiles>

在哪配置?

有两个地方可以配置profile,分别是settings.xml文件和项目的POM文件。

激活方式

默认配置被默认激活

如果仅配置了activeByDefault标签,则配置被默认激活。

基于环境信息激活

针对系统环境判断,支持采用多种方式进行匹配,如果activation标签中有一项不匹配,则不会进行激活。

<profiles>  
    <profile>  
        <id>disable-javadoc-doclint</id>  
        <activation>            
	        <jdk>[1.8,)</jdk>  
            <os>                
	            <!-- 配置os信息 -->  
            </os>  
            <property>                
	            <!-- 根据属性值进行激活匹配 -->  
            </property>  
        </activation>  
        <properties>            
	        <javadoc.opts>-Xdoclint:none</javadoc.opts>  
        </properties>  
    </profile>  
</profiles>
命令行激活

列出活动的profile

mvn help:active-profiles

指定激活某个具体profile

mvn compile -P<profile id>

资源属性过滤

可以在profile中配置是否对资源文件进行过滤,资源文件过滤的作用是对资源文件中的占位符${}用配置的值进行替换,方便对属性值的统一管理。

示例配置如下:

<profile>  
    <id>disable-javadoc-doclint</id>  
    <activation>        
	    <jdk>[1.8,)</jdk>  
    </activation>  
    <properties>        
	    <javadoc.opts>-Xdoclint:none</javadoc.opts>  
    </properties>  
    <build>        
	    <resources>  
            <resource>  
                <!-- 资源文件目录 -->  
                <directory>src/main/resources</directory>  
                <!-- 是否开启过滤 -->  
                <filtering>true</filtering>  
                <!-- 包含的文件 -->  
                <includes>  
	                <!-- 已properties为例,只能处理properties文件 -->
                    <include>*.properties</include>  
                </includes>  
                <!-- 排除的文件 -->  
                <excludes>  
                    <exclude>test.properties</exclude>  
                </excludes>  
            </resource>  
        </resources>  
    </build>  
</profile>

如何处理jar包冲突

冲突表现形式

在发生冲突时,一般程序会报错,但在不同阶段报的错误是不同的。
编译时
如果在编译时检测到jar包冲突,会以抛异常的方式告知开发者,异常类型为:找不到类。
运行时

  1. 找不到方法
  2. 没报错但结果不对(版本问题)

解决办法

IDEA中的maven helper插件

通过该插件可以检测出当前项目中同一个jar包的不同版本冲突,我们可以根据提示通过exclusions标签来排除冲突的jar包。
该插件仅可以检测出jar包的版本冲突。

Maven的enforcer插件

使用maven的enforcer插件既可以检测同一个jar的不同版本冲突,还可以检测不同jar包中同名的类。

这里提供一份配置,该配置会自动绑定指定的生命周期,并且在运行生命周期时自动去执行。

<build>  
    <plugins>  
        <plugin>  
            <groupId>org.apache.maven.plugins</groupId>  
            <artifactId>maven-enforcer-plugin</artifactId>  
            <version>3.0.0</version>  
            <dependencies>                
	            <dependency>  
                    <groupId>org.codehaus.mojo</groupId>  
                    <artifactId>extra-enforcer-rules</artifactId>  
                    <version>1.5.1</version>  
                </dependency>  
                <!-- <dependency>-->  
                <!--   <groupId>org.sonatype.ossindex.maven</groupId>-->         
                <!--   <artifactId>ossindex-maven-enforcer-rules</artifactId>--> 
                <!--   <version>3.2.0</version>-->                
                <!-- </dependency>-->            
            </dependencies>  
            <executions>                
            <execution>  
                    <!-- 检测 Maven 版本 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html -->                    
                    <id>enforce-versions</id>  
                    <phase>install</phase>  
                    <goals>                        
	                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        
                    <rules>  
                        <requireMavenVersion>  
                            <version>3.5.0</version>  
                            <message>                                    
                            <![CDATA[You must use maven 3.5.0]]>  
                            </message>  
                        </requireMavenVersion>  
                        <requireJavaVersion>                                
                            <version>1.8</version>  
                                <message>                                    
                                <![CDATA[You are running an older version of Java. This application requires at least JDK 1.8.]]>  
                                </message>  
                        </requireJavaVersion>  
                        </rules>  
                    </configuration>  
                </execution>  
                <execution>                    
                <!-- 检查依赖重复声明的情况 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/banDuplicatePomDependencyVersions.html -->                    
                    <id>enforce-no-duplicate-declared-dependencies</id>  
                    <goals>                        
                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        
                    <rules>  
                            <banDuplicatePomDependencyVersions/>  
                    </rules>  
                    </configuration>  
                </execution>  
                <execution>                    
                <!-- 检查依赖版本情况 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/dependencyConvergence.html -->                    
                    <id>enforce-dependencyConvergence</id>  
                    <goals>                        
                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        
                    <rules>  
                            <dependencyConvergence/>  
                    </rules>  
                    </configuration>  
                </execution>  
                <execution>                    
                <!-- 确保父子模块的版本是一致的。 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/reactorModuleConvergence.html -->                    
                    <id>enforce-reactorModuleConvergence</id>  
                    <goals>                        
                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                       
                    <rules>  
                            <reactorModuleConvergence>  
                                <message>父子模块的版本必须一直。</message>  
			        <ignoreModuleDependencies>true</ignoreModuleDependencies>  
                        </reactorModuleConvergence>  
                        </rules>  
                        <fail>true</fail>  
                    </configuration>  
                </execution>  
                <execution>                    
                <!-- 确保直接引用的依赖不比间接解析出来的依赖版本低。 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/requireUpperBoundDeps.html -->                    
                    <id>enforce-requireUpperBoundDeps</id>  
                    <goals>                        
                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        
                    <rules>  
                            <requireUpperBoundDeps>  
                            </requireUpperBoundDeps>                        
                            </rules>  
                    </configuration>  
                </execution>               
                <execution>  
                    <!-- 检测依赖 -->  
                    <!-- https://maven.apache.org/enforcer/enforcer-rules/bannedDependencies.html -->                    
                    <id>enforce-banned-dependencies</id>  
                    <goals>                        
                    <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        
                    <rules>                          
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    
                                <exclude>org.projectlombok:lombok</exclude>  
                                </excludes>  
                                <includes>                                    
		                        <include>org.projectlombok:lombok:*:*:provided</include>  
                                </includes>  
                                <message>                                    <![CDATA[Lombok 不能在 runtime 被引入!请使用 provided。]]>  
                                </message>  
                            </bannedDependencies>  
  
                            <!-- log4j -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>log4j</exclude>  
                                    <exclude>org.slf4j:slf4j-log4j12</exclude>  
                                </excludes>  
                                <message><![CDATA[不能使用 Log4j。]]></message>  
                            </bannedDependencies>  
  
                            <!-- commons log -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>commons-logging</exclude>  
                                </excludes>  
                                <message><![CDATA[不能使用 commons logging。]]></message>  
                            </bannedDependencies>  
  
                            <!-- jdk log -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>org.slf4j:slf4j-jdk14</exclude>  
                                </excludes>  
                                <message><![CDATA[不能使用 jdk log。]]></message>  
                            </bannedDependencies>  
  
                            <!-- logback 1.2.0+ -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>ch.qos.logback:*:[,1.2.0):jar</exclude>  
                                </excludes>  
                                <message><![CDATA[必须使用 logback 1.2.0+。]]></message>  
                            </bannedDependencies>  
  
                            <!-- slf4j 1.7.25+ -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>org.slf4j:*:[,1.7.25):jar</exclude>  
                                </excludes>  
                                <message><![CDATA[必须使用 slf4j 1.7.25+。]]></message>  
                            </bannedDependencies>  
  
                            <!-- Javassist 3.24.0-GA+ -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>org.javassist:javassist:[,3.24.0-GA):jar</exclude>  
                                    <exclude>javassist:javassist</exclude>  
                                </excludes>  
                                <message><![CDATA[必须使用 Javassist 3.24.0-GA+。]]></message>  
                            </bannedDependencies>  
  
                            <!-- Jakarta Validation -->  
                            <bannedDependencies>  
                                <searchTransitive>true</searchTransitive>  
                                <excludes>                                    <exclude>javax.validation:validation-api:[,2.0.1.Final):jar</exclude>  
                                    <exclude>org.hibernate.validator:hibernate-validator:[,6.1.5.Final):jar</exclude>  
                                    <exclude>org.hibernate.validator:hibernate-validator-annotation-processor:[,6.1.5.Final):jar</exclude>  
                                    <exclude>org.hibernate:hibernate-validator</exclude>  
                                </excludes>  
                                <message>                                    <![CDATA[必须使用 jakarta.validation:jakarta.validation-api:2.0.1+ 和 Hibernate Validator 6.1.5.Final+(org.hibernate.validator:hibernate-validator:6.1.5.Final 和 org.hibernate.validator:hibernate-validator-annotation-processor:6.1.5.Final)。不能使用 javax.validation:validation-api 和 org.hibernate:hibernate-validator。]]>  
                                </message>  
                            </bannedDependencies>  
                            <!-- groupId[:artifactId][:version][:type][:scope][:classifier] -->  
                        </rules>  
                        <fail>true</fail>  
                    </configuration>  
                </execution>  
                <execution>                    <!-- 检测重复类定义。 -->  
                    <!-- https://www.mojohaus.org/extra-enforcer-rules/banDuplicateClasses.html -->                    <id>enforce-ban-duplicate-classes</id>  
                    <goals>                        <goal>enforce</goal>  
                    </goals>  
                    <configuration>                        <rules>  
                            <banDuplicateClasses>  
                                <scopes>  
                                    <scope>compile</scope>  
                                </scopes>  
                                <findAllDuplicates>true</findAllDuplicates>
                                <!-- 如果注释掉这个,会检查同名类。如果不注释,当包名不同类名相同时,会忽略 -->  
                                <ignoreWhenIdentical>true</ignoreWhenIdentical>  
                                <ignoreClasses>                                    <ignoreClass>module-info</ignoreClass>  
                                    <ignoreClass>org.apache.commons.logging.*</ignoreClass>  
                                </ignoreClasses>  
                            </banDuplicateClasses>  
                        </rules>  
                        <fail>true</fail>  
                    </configuration>  
                </execution>  
                <!-- <execution>-->  
                <!--   &lt;!&ndash; 依赖漏洞检查 &ndash;&gt;-->                <!--   <id>vulnerability-checks</id>-->                <!--   <goals>-->                <!--     <goal>enforce</goal>-->                <!--   </goals>-->                <!--   <configuration>-->                <!--     <rules>-->                <!--       <banVulnerable implementation="org.sonatype.ossindex.maven.enforcer.BanVulnerableDependencies"/>-->                <!--     </rules>-->                <!--   </configuration>-->                <!-- </execution>-->            </executions>  
        </plugin>  
    </plugins>  
</build>

引入maven体系外jar包

主要是通过mvn install:install-file命令将jar包安装到本地仓库中。

mvn install:install-file -Dfile=jar_path \
-DgroupId=自己设定
-DartifactId=自己设定
-Dversion=版本
-Dpackage=jar

通过上面的命令将jar包安装到本地仓库中,然后就可以通过maven直接引入了。