Maven 简明笔记

Maven 主要功能

Maven 是专门用于管理和构建 Java 项目的工具,它的主要功能有:

  • 提供了一套标准化的项目结构
  • 提供了一套标准化的构建流程(编译,测试,打包,发布…)
  • 提供了一套依赖管理机制

标准化的项目结构

不同 IDE 之间,项目结构不一样,不通用
01-不同IDE之间项目结构不一致.png

所有 IDE 使用 Maven 构建的项目结构完全一样,所有 IDE 创建的 Maven 项目都可以通用

Maven 的项目结构
02-Maven项目结构.png

标准化的构建流程

源代码⇒编译⇒测试⇒打包⇒发布,Maven 提供了一套简单的命令来完成项目构建

提供了一套依赖管理机制

比如 JDBC,需要使用的 MySQL 的驱动包,依赖管理其实就是管理你项目所依赖的第三方资源(Jar 包、依赖),原先我们是如何操作的呢:

  1. 下载 jar 包
  2. 将 jar 包复制到 lib 文件夹里
  3. 右键 jar 包,作为库

那 Maven 是如何管理依赖的呢

  1. Maven 使用标准的 坐标 配置来管理各种依赖
  2. 只需要简单的配置就可以完成依赖管理
    03-通过坐标管理依赖.png

Maven 简介

Apache Maven 是一个项目管理和构建工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建、报告和文档

仓库分类

  • 本地仓库
  • 中央仓库:有 Maven 团队维护的全球唯一的仓库(免费的开源的 jar 包)
  • 远程仓库(私服):一般有公司团队搭建的私有仓库(可以存放一下自己的公司的和一些可能具有版权的 jar 包)

查找流程:首先会查找本地仓库,如果本地仓库没有,则去中央仓库查找是否有,有的话就会 自动下载 到本地仓库

Maven 的安装和配置

  1. 解压即可安装
  2. 配置环境变量

下图中的 Maven 文件夹呢就是包含 bin 文件夹的文件夹
04-配置Maven环境路径1.png

将 bin 目录添加到 Path 目录中
05-配置Maven环境路径2.png

  1. 配置本地仓库:修改 conf/setting.xml 中的 <localRepository> 为其指定一个目录

06-指定本地仓库路径.png

注意:为了保守起见,在 Intellij 中也对 Maven 的本地路径配置一下:)
12-指定本地仓库路径2.png

  1. 配置阿里云私服:修改 conf/setting.xml 中的 <mirrors> 标签,为其添加如下子标签
1
2
3
4
5
6
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</mirror>

07-配置阿里云远程仓库.png

Maven 的基本使用

Maven 的常用命令

  • compile:编译
  • clean:清理,删除前面编译产生的 target 目录
  • test:测试,执行 test 文件夹下的代码
  • package:打包
  • install:安装

在含有 pom.xml 文件的目录下,进入 PowerShell

1
2
3
4
5
mvn compile
mvn clean
mvn package
mvn tast
mvn install

Maven 的生命周期

Maven 对项目构建的生命周期划分为三套

  • clean:清理工作
  • default:核心工作,例如编译,测试,打包,安装等
  • site:产生报告,发布站点等

08-Maven的生命周期.png

比如说执行 install,就会自动执行 compile,但是不会自动执行 clean(因为这是两套不同的生命周期)

依赖管理

使用坐标导入 jar 包

  1. 在 pom.xml 中编写 <dependencies> 标签
  2. <dependencies> 标签中使用 <dependency> 来引入坐标
  3. 定义坐标的 groupId,artifactId,version
  4. 点击刷新按钮,是坐标生效(或者对 IDE 进行配置,每次变更自动生效)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 导入 mysql 驱动jar包-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
</dependencies>

比如去找 MySQL 的 Maven 配置信息(浏览器搜索 mysql maven),比如从以下网页中找到了:MySQL Connector Java

还为我们提供了 maven 需要使用的信息
09-从官网获得Maven的配置信息.png

快速导入坐标信息到 pom.xml

如果本地仓库就有相应的 jar 包,那么直接可以通过搜索 jar 包的名字来导入(即可自动导入模板)

  1. 在 pom.xml 文件中,Alt+Insert
  2. 选择依赖项模板,自动为我们添加模板

10-快速插入依赖项模板.png

依赖范围

通过设置坐标依赖范围(scope),可以设置对应 jar 包的作用范围:编译环境、测试环境、运行环境

编译环境:在主工程 java 文件夹中可以使用
测试环境:在测试文件夹 test 中可以使用
运行环境:

依赖范围的取值有以下六种,默认值是 compile(其实范围也是最大的)

分模块开发与设计

将原始模块按照功能拆分为若干个子模块,方便模块间的相互调用,接口共享

01-分模块开发思想.png

Intellij 中同时导入多个模块方式如下:
02-Intellij同时导入多个模块.png

1、项目准备:之前做好的 SSM 整合的项目 maven_02_ssm 进行讲解
2、新建一个模块:maven_03_pojo

1)新建 com.itheima.domain 包
2)将 maven_02_ssm 中的 domain 下的 Book 实体类剪切至 maven_03_pojo 下的 domain 包下
3)此时 maven_02_ssm 将无法运行,因为缺少了 Book 实体类
4)现在要做到是:如何在 maven_02_ssm 中访问 / 加载 maven_03_pojo 下的 Book 实体类呢?

maven_03_pojo 模块中 pom.xml 的坐标如下

1
2
3
<groupId>com.itheima</groupId>  
<artifactId>maven_03_pojo</artifactId>
<version>1.0-SNAPSHOT</version>

那么我们在 maven_02_ssm 中引入上面的坐标

1
2
3
4
5
6
<!--依赖domain运行-->  
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_03_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

此时就将 maven_03_pojo 模块引入进来了,此时 maven_02_ssm 也没有报错了

总结:将一个模块中的一部分功能抽取出来单独做一个模块,然后在原来的使用方去引用这个抽取出来的模块,这样就做成了两个模块

但是此时 02 模块会有问题?为什么呢
因为通过坐标导入,会将相应的资源下载到本地仓库,02 模块引入了 03 模块,但是本地仓库里面却找不到 03 的资源。因此,我们还需要将 03 模块 install 到本地仓库中

03-导入坐标之后需要安装到本地仓库.png

安装完之后,本地仓库中就可以找到模块 03 的资源了。此时我们在 compile 一下 02 模块,若能够编译成功,说明没有问题了

依赖管理

如果一个模块 A 依赖了模块 B,而 B 模块依赖了其他的东西,那么这个 A 模块可以直接使用这些东西

直接依赖:在当前项目中通过依赖配置建立的依赖关系
简介依赖:被依赖的资源如果依赖其他资源,当前项目简介依赖其他资源

依赖冲突

  • 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
  • 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
  • 特殊优先:当同级配置类相同资源的不同版本,后配置的覆盖先配置的

04-依赖层级关系.png

可以通过此处查看项目中的依赖关系
05-Intellij中查看依赖层级关系.png

可选依赖

比如说 02 模块引用了 04 模块,04 模块中引用了几个坐标。现在的需求是,我不想让 02 模块能够加载或引用 04 模块中的坐标,怎么处理呢?

那么在 04 模块中,对如下这个坐标进行处理

1
2
3
4
5
6
7
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_03_pojo</artifactId>
<version>1.0-SNAPSHOT</version>
<!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递性-->
<optional>true</optional>
</dependency>

其实这个需要就是想要某个坐标没有传递性

排除依赖

比如引用了 maven_04_dao 坐标,但是排除这个坐标下的另外两个坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_04_dao</artifactId>
<version>1.0-SNAPSHOT</version>
<!--排除依赖是隐藏当前资源对应的依赖关系-->
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>

那么可选和排除有什么区别呢:

  • 用的可选,别人引用了我的坐标,但是不知道我背后引用了哪些坐标;对外隐藏当前所依赖的资源
  • 用的排除,别人是知道我背后引用了那些坐标的;主动断开依赖的资源,被排除的资源无需指定版本

聚合

06-聚合的引入.png

比如:上面的三个模块都是依赖 pojo 模块的,假如我们更新了 pojo 模块,上面三个模块会及时更新吗?如果 pojo 因为更新出现了问题,上面三个模块能够及时发现吗?

聚合:将多个模块组织成一个整理,同时进行项目构建的过程称为聚合(其实有点像事务的概念)
聚合工程:通常是一个不具有业务功能的 “空” 工程(仅有一个 pom 文件)
作用:使用聚合工程可以将多个模块编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建;当工程中某个模块发生更新时,必须保障工程中与已更新模块关联的模块同步更新,此时可以使用聚合工程来解决批量模块同步构建的问题

1)创建新 Maven 模块
2)聚合工程的特点:在 pom.xml 中,将打包方式设置为 pom

1
<packaging>pom</packaging>

3)设置管理模块的模块名称

1
2
3
4
5
6
7
8
<!--设置管理模块名称
..表示当前文件pom.xml文件的上一级文件
-->
<modules>
<module>../maven_02_ssm</module>
<module>../maven_03_pojo</module>
<module>../maven_04_dao</module>
</modules>

07-聚合-引入子模块.png

08-聚合后各层级的关系.png

4)进行同步编译 compile

09-聚合后进行同步编译.png

继承

概念:继承描述的是两个工程间的关系,与 Java 中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承

作用:简化配置;减少版本冲突

1)继承关系在子类中描述

1
2
3
4
5
6
7
<!--配置当前工程继承自parent工程-->  
<parent>
<groupId>com.itheima</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-RELEASE</version>
<relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>

此时,就可以继承父工程中依赖的坐标了

2)父工程中的坐标都必须要被所有子工程继承吗?不一定
可以在父工程 pom 文件中通过 dependencyManagement 来指定这是一个可选的坐标

1
2
3
4
5
6
7
8
9
10
11
<!--定义依赖管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

如果子工程中想要引用的话就在 pom 中加上相应的坐标,但是注意不要加版本号,因为他会自动继承父类中坐标的版本号;而对于其他子工程就不会自动继承引用这个坐标

1
2
3
4
5
<dependency>  
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

3)子工程继承父工程中的坐标,只要父工程中坐标的版本号一改,所有子工程中对应的版本号都会改

聚合与继承的区别

  • 作用
    • 聚合用于快速构建项目
    • 继承用于快速配置
  • 相同点
    • 聚合与继承的 pom.xml 文件打包方式均为 pom,可以将两种关系制作到同一个 pom 文件中
    • 聚合与继承均属于设计型模块,并无实际的模块内容
  • 不同点
    • 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
    • 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己

属性

10-属性问题的引入.png

1)定义属性

1
2
3
4
<!--定义属性,标签名可以自定义-->  
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
</properties>

2)在定义坐标时,可以直接使用变量

1
2
3
4
5
6
7
8
9
10
11
<dependency>  
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

3)这样就好了呀,以后可以直接从这儿就可以看到各种坐标的版本

1
2
3
4
5
6
7
<!--定义属性-->  
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
<junit.version>4.12</junit.version>
<mybatis-spring.version>1.3.0</mybatis-spring.version>
<!--<jdbc.url>jdbc:mysql://127.0.0.1:3306/ssm_db</jdbc.url>-->
</properties>

版本管理

比如如下为某一工程 pom.xml 中的坐标,其中的 version 有什么用呢?

1
2
3
4
<groupId>com.itheima</groupId>  
<artifactId>maven_02_ssm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
  • 工程版本
    • SNAPSHOT(快照版本)
      • 项目开发过程中临时输出的版本,称为快照版本
      • 快照版本会随着开发的进展不断更新
    • RELESE(发布版本)
      • 项目开发到进入阶段里程碑后,向团队外部发布较为稳定的版本,这种版本所对应的构建文件时稳定的,即便进行功能的后续开发,也不会改变当前发布版本的内容,这种版本称为发布版本
  • 发布版本
    • alpha 版
    • beta 版
    • 纯数字版

多环境配置

011-多环境配置.png

maven 提供配置多种环境的设定,帮助开发者使用过程中快速切换环境

1)在父工程 pom.xml 中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!--配置多环境-->
<profiles>
<!--开发环境-->
<profile>
<id>env_dep</id>
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
<!--设定是否为默认启动环境-->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!--生产环境-->
<profile>
<id>env_pro</id>
<properties>
<jdbc.url>jdbc:mysql://127.2.2.2:3306/ssm_db</jdbc.url>
</properties>
</profile>
<!--测试环境-->
<profile>
<id>env_test</id>
<properties>
<jdbc.url>jdbc:mysql://127.3.3.3:3306/ssm_db</jdbc.url>
</properties>
</profile>
</profiles>

2)对工程进行 install,然后可以查看项目构建好的 war 包,双击 war 包,进入 WEB-INF 文件夹 ⇒ classes 文件夹 ⇒ jdbc.properties 文件,查看配置是否生效

如果要更换环境,可以将设置默认启动环境的那几行代码切换一下位置,比如切换到测试环境中,那么 install 后,默认就是测试环境的配置了

或者可以不用挪动那几行代码,直接使用 Maven 指令来表明我们将使用 env_dep 环境来进行 install,如下图所示
012-Maven指令处理多环境.png

013-Maven指令处理多环境-2.png

跳过测试

跳过测试:跳过所有测试
014-跳过测试.png
跳过测试:指定跳过某些内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>false</skipTests>
<!--排除掉不参与测试的内容-->
<excludes>
<exclude>**/BookServiceTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>