概念

Maven 是一个依赖管理工具,为 Java 项目提供构建和依赖管理支持的工具

简单来说就是 jar包的仓库,依赖对应的 jar 包能够自动下载,不用自己到处找依赖 jar 包

配置 maven

下载 maven 下载连接

下载后解压到一个目录

核心配置文件 conf/settings.xml

配置本地仓库位置

默认本地仓库位置 用户家目录/.m2/repository

自定义本地仓库位置

在 conf/settings.xml 配置文件 找到 localRepository标签

<localRepository>写入本地仓库的目录</localRepository>

注意:本地仓库本身也需要使用一个非中文、没有空格的目录

配置镜像源

maven 默认访问国外的中心仓库,下载速度较慢,要配置阿里云的镜像仓库

在 conf/settings.xml 配置文件 找到 mirror标签

原来 id 为 maven-default-http-blocke 的镜像注释或删除掉

加入阿里云的镜像

<mirror>
  <id>nexus-aliyun</id>
  <mirrorOf>central</mirrorOf>
  <name>Nexus aliyun</name>
  <url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

配置 jdk

在 conf/settings.xml 配置文件 找到 profiles标签

在里面加入

<profile>
  <id>jdk-1.8</id>
  <activation>
    <activeByDefault>true</activeByDefault>
    <jdk>1.8</jdk>
  </activation>
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  </properties>
</profile>

配置环境变量

确保要配置好 java 环境

linux 系统

/etc/profile 文件下加入环境变量

# 填写 maven 所在的目录
export MAVEN_HOME=/usr/local/apache-maven-3.8.5 
export PATH=$PATH:$MAVEN_HOME/bin

window 系统

右键此电脑点击选择属性 ->高级系统设置->高级->环境变量

新建环境变量 :变量名 MAVEN_HOME 变量值 maven的路径

配置PATH:%MVNEN_HOME/bin%

配置验证

输入 mvn -v 查看是否有版本号

例如

idea 配置

设置->找到 maven 设置 配置好maven 主路径,设置文件,本地仓库

创建 maven

坐标

首先认识 maven 坐标

maven 中坐标是资源的唯一标识

组成:

  • groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:org.mybatis)
  • artifactId:定义当前Maven项目名称(通常是模块名称,例如 mybatis、junit)
  • version:定义当前项目资源版本号

例如 mybatis 和 mysql 的依赖 jar 包

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

创建项目

使用命令创建项目

mvn archetype:generate 

按照下面提示

Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): 7:【直接回车,使用默认值】

Define value for property 'groupId': com.example.maven

Define value for property 'artifactId': demo-maven-java

Define value for property 'version' 1.0-SNAPSHOT: :【直接回车,使用默认值】

Define value for property 'package' com.example.maven: :【直接回车,使用默认值】

Confirm properties configuration: groupId: com.example.maven artifactId: demo-maven-java version: 1.0-SNAPSHOT package: com.atguigu.maven Y: :【直接回车,表示确认。如果前面有输入错误,想要重新输入,则输入 N 再回车。】

建好项目目录结构

依赖在 pom.xml 配置

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

  <!-- 当前Maven工程的坐标 -->
  <groupId>com.example.maven</groupId>
  <artifactId>demo-maven-java</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!-- 项目打包方法:可选 jar war pom -->
  <packaging>jar</packaging>

  <name>demo-maven-java</name>
  <url>http://maven.apache.org</url>

  <properties>
    <!-- 工程构建过程中读取源码时使用的字符集 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- 当前工程所依赖的jar包 -->
  <dependencies>
    <!-- 在dependency标签内使用具体的坐标
        依赖我们需要的一个jar包
        例如这里为 junit
     -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <!-- scope 标签配置依赖的范围 
					默认值是 compile
          test 在测试环境生效
       -->
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

要导入其他依赖包 添加该包的坐标信息到 dependencies 下

查找其他包的信息:https://mvnrepository.com/

例如 mybatis

选择版本信息,推荐使用人数多的

复制坐标信息添加到 pom.xml 即可

创建 web 项目

使用命令

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DarchetypeVersion=1.4

目录结构和上面的目录在java同目录下多了一个 webapp 目录,用来编写web工程

构建命令

构造命令要在 maven 项目根目录下执行,即 pom.xml 目录下

命令 描述
mvn clean 清理操作:删除 target 目录
mvn compile / mvn test-compile 编译操作:存放的目录 target/classes ; 测试程序编译 target/test-classes
mvn test 测试操作:报告存放的目录:target/surefire-reports
mvn package 打包操作:结果jar 包,存放的目录:target
mvn install 安装操作:构建过程中生成的 jar 包存入 Maven 本地仓库,路径是根据它的坐标生成

跳过测试

mvn 指令 -D skipTests

idea 项目用可视化 maven 构建命令

idea 里跳过测试

依赖管理

依赖的范围

maven的依赖范围用 <scope>元素表示的,例如上面的 junit scope为test

依赖范围有六种: compile、test、provided、runtime、import和system

常用的前面4种

  1. compile:编译依赖, 是默认的依赖范围,在 main 和 test 都可以访问这个范围的依赖,服务器可访问,布署到 tomcat下时, 把这个依赖放置在 WEB-INF 下的 lib 文件夹里面
  2. test:测试依赖,是测试使用的。test目录下可访问,main目录下的代码不能访问这个依赖,服务器不可访问
  3. provided:提供依赖 在 main 和test 目录的代码可以访问这个依赖,服务器不可访问
  4. runtime:运行依赖,main目录下的代码不能访问这个依赖, test目录可以访问,服务器可访问

作用域

依赖范围 对于编译执行环境有效 对于测试执行环境有效 对于运行时执行环境有效 例子
compile spring-core
test junit
provided servlet-api
runtime jdbc

总结:

  1. compile是缺省设置,需要在开发的整个过程中都用到

  2. test 只是在测试过程中用到,所以不需要在main目录下使用,也不需要发布到服务器中

  3. provided意思是,这种jar包是tomcat已经提供的了,所以不需要像compile那样打包时再打进去。例如servlet-api、jsp-api,此时,如果强行改为缺省的compile,则可能会引起冲突报错

依赖的传递

如果我们项目引用的 jar 包 ,该 jar 包又引用了其他 jar 包,这就是传递依赖,默认编译项目时 Maven 会把直接引用和间接引用的Jar包都下载到本地仓库

传递的原则

在 A 依赖 B,B 依赖 C 的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。

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

传递的冲突

项目 需要引入依赖包A,依赖包A又引入了依赖包C,那么B是项目的直接依赖,C是项目的传递依赖。如果项目还需要引入依赖包B,依赖包B也引用了依赖包C,当依赖包A引用的C和依赖包B引用的C版本不同时,则发生了依赖冲突

Maven中采用了两种避免冲突的策略:

  1. 短路径优先:哪一个传递依赖离它最近则就优先选择它
  2. 声明优先:(上面图情况)谁先声明的就先选择谁,即在 pom.xml 里先写的优先

因此在Maven中实际上是不存在依赖冲突的

依赖的排除

项目A依赖于B,B依赖于C,但有可能C依赖是不兼容的,会对项目造成一定的影响。此时,我们可以使用关键字exclusion排除C依赖

<dependency>
  <groupId>com.example.maven</groupId>
  <artifactId>demo-maven-java</artifactId>
  <version>1.0-SNAPSHOT</version>
  <scope>compile</scope>
  <!-- 使用excludes标签配置依赖的排除  -->
  <exclusions>
    <!-- 在exclude标签中配置一个具体的排除 -->
    <exclusion>
      <!-- 指定要排除的依赖的坐标(不需要写version) -->
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
</dependency>

继承和聚合

继承

Maven工程之间,A 工程继承 B 工程,本质上是 A 工程的 pom.xml 中的配置继承了 B 工程中 pom.xml 的配置

使用继承的目的是为了消除重复性,常用的是把子模块 pom 中很多相同的依赖配置提取出来,统一锁定在父模块的pom中。如:grouptId、artifactId、version等等。在使用的时候子模块会直接继承父模块的依赖版本号,子模块中不再需要指定具体版本号,方便统一管理项目的依赖问题

操作

父工程

工程创建好之后,要修改它的打包方式:

<groupId>com.example.maven</groupId>
<artifactId>demo-maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>

<!-- 当前工程作为父工程,它要去管理子工程,所以打包方式必须是 pom -->
<packaging>pom</packaging>

注意的是父模块坐标中的packaging必须是pom类型,否则子模块就不会继承

创建子工程

在父工程目录里,IDEA右击项目选择 Module maven项目 或者 mvn archetype:generate 命令来创建模块工程

例如

子模块 pom 配置

<!-- 使用parent标签指定当前工程的父工程 -->
<parent>
  <!-- 父工程的坐标 -->
  <groupId>com.example.maven</groupId>
  <artifactId>demo-maven-parent</artifactId>
  <version>1.0-SNAPSHOT</version>>
</parent>

父工程配置依赖统一管理

<!-- 集中定义依赖版本号 -->
<properties>
  <spring.version>5.2.6.RELEASE</spring.version>
  <junit.version>4.12</junit.version>
</properties>

<!-- 版本锁定,当子模块中有需要并且自行添加了具体依赖后才有效,
    它仅仅是起到锁定作用,不下载依赖包 -->
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
  </dependencies>
</dependencyManagement>

子模块设置依赖

<!--依赖包的下载仍然有dependencies管理-->
<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <!-- 版本号由父模块里面统一指定不再需要特别指定 -->
    <!--<version>4.12</version>-->
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
  </dependency>
</dependencies>

聚合

使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目

一键执行 Maven 命令:很多构建命令都可以在“总工程”中一键执行

配置聚合之后,各个模块工程会在总工程中展示一个列表,让项目中的各个模块一目了然

配置:在总工程中配置 modules 即可

前面继承例子中的Child1、Child2和Child3这三个模块,我们对它进行聚合

<!--在父模块中聚合-->
<modules>
  <module>Child1</module>
  <module>Child2</module>
  <module>Child3</module>
</modules>