什么是 Maven
java 中的 jar 包依赖管理工具,类似于 Node.js 中的 npm 包管理工具 本质是一个项目管理工具,将项目抽象化成一个对象模型(Project Object Model / POM)
作用:
- 项目构建:提供标准的,跨平台的项目构建方式
- 依赖管理:方便快捷的管理项目中的依赖资源(jar包),避免资源间的版本冲突问题
Maven 的资源坐标在线查找:mvnrepository.com/
配置
- 环境变量
- MAVEN_HOME:Maven 安装目录(D:\Program Files\apache-maven-3.8.5)
- Path 中新建:%MAVEN_HOME%\bin
核心概念
-
pom模型 项目对象模型,在每个 Maven 项目中都有一个 pom.xml 文件,用于管理整个项目, 将项目作文一个对象来管理。
-
仓库 用于存储资源,包含各种 jar 包
- 本地仓库 自己计算机本地的仓库
- 中央仓库 Maven 团队自己维护的仓库
- 私服 公司或者组织自己建立的仓库,从中央仓库中获取资源和包含自有的资源,提供给本公司或者组织内的人使用
- 坐标 Maven 中对资源的定位,一个坐标唯一定位一个资源
- groupId(组织ID):定义当前 Maven 项目隶属的组织(通常是域名的反写:org.apache)
- artifactId(项目ID):定义当前 Maven 项目的名称(通常是模块名称:CRM)
- version(版本号):定义当前项目的版本号
坐标的书写例子
<dependency>
<groupId>com.baidu</groupId>
<artifactId>car</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
本地仓库配置
- 默认的 Maven 本地仓库的配置 C:\Users\Lenovo.m2\repository // 用户文件夹下的 .m2/repository
- 修改本地长仓库的配置
- 打开 Maven 的配置文件:Maven安装目录\conf\setting.xml
- 加入以下配置
<!-- localRepository 标签中写入本地仓库的地址 -->
<localRepository>F:\Maven\repository</localRepository>
远程仓库的配置
国内建议使用阿里的中央仓库,访问速度会比较快
<!-- 镜像配置集合 -->
<mirrors>
<!-- 具体的镜像 -->
<mirror>
<!-- 此镜像的唯一标识,用来区分不同的镜像 -->
<id>aliyunmaven</id>
<!-- 对那种仓库进行镜像,简单说就是代替哪个仓库 -->
<mirrorOf>*</mirrorOf>
<!-- 镜像的名称 -->
<name>阿里云公共仓库</name>
<!-- 镜像地址 -->
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
Maven 中常用的命令
- mvn help:system
- 查看当前 Maven 使用的与命令相关的插件(compile,clean,install)情况,插件不存在则会去安装插件
- mvn compile
- 编译项目,编译完成之后在项目的跟过呢目录下生成一个 target 文件夹
- mvn test
- 执行测试命令,对项目进行编译测试,生成测试报告
- mvn package
- 执行打包命令,根据 pom.xml 文件打包成 jar/war 文件
- 打包之前会先进行项目编译,项目测试,在测试通过之后才会开始打包
- 跳过测试直接打包(打包之前先执行 clean):mvn clean package -D maven.test.skip=true
- mvn install
- 将当前的模块作为依赖安装到本地仓库中,安装完之后可以作为依赖被其他的模块引入
- 同样会先执行测试步骤,测试通过之后才会安装到本地仓库中
- 跳过测试步骤安装:mvn install -D maven.test.skip=true
在 IEDA 中配置 Maven
- IEDA 中默认集成了 Maven,但是在开发的过程中我们一般不使用 IEDA 自带的 Maven,而是使用自己下载安装的。
- IEDA2021 中使用的 Maven 版本最好未 3.6.3 或者以下,最新的版本(3.8.5/3.8.6)会报错。
设置:
- IEDA -> File -> setting -> 搜索Maven
- 设置 Maven 的安装路径,使用的设置文件,本地仓库
配置 tomcat webapp开发服务器:
- 在 webapp 项目的 pom.xml 文件中添加构建依赖
<build>
<plugins>
<!-- 开发环境下启动 tomcat 插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<!-- 端口 -->
<port>8082</port>
<!-- 虚拟路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
- 在右边的 Maven 工具栏中刷新,等待插件下载完成
- 点开 Maven 工具栏中对应项目的 Plugins
- 找到 tomcat7 (7代表版本,不同的版本可能不同)
- 找到 tomcat:run,点击打开会启动一个开发服务器
- 也可以将该命令配置上方的工具栏 configurations 中,方便使用
依赖
依赖的传递性
- 间接依赖 A 中引用了 B,C 引用了 A,C 中也可以使用 B。
- 直接依赖 A 中直接引用了 B。
依赖的有效性遵循以下原则
- 路径优先:当依赖中出现相同的资源时,层级越深优先级越低,层级越浅优先级越高
- 声明优先:当资源在相同层级被依赖时,配置的顺序越靠前优先级约高
- 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖前配置的
依赖隐藏与排除
依赖隐藏
把项目作为依赖提供给其他人使用,但是不想让其他人知道本项目中使用的依赖有哪些 将需要隐藏的依赖加上 true 的配置项
使用别人的依赖,但是依赖的开发者不想让你知道这个依赖中使用了什么资源
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<optional>true</optional>
</dependency>
排除依赖
指的时主动断开依赖的资源,被排除的资源无需指定版本——不需要
使用别人的依赖,但是我主动排除掉该依赖的使用的某个资源
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<!-- 排除,需要依赖的 groupId 和 artifactId -->
<exclusions>
<exclusion>
<groupId>org.hamorest</groupId>
<artifactId>hamorest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
依赖作用的范围
就是每个依赖的作用范围,比如测试使用 junit 依赖只需要在测试的时候使用,在项目运行和编译打包中不需要。 springBoot 是开发中使用框架,在运行打包编译是需要,但是测试的时候可能不需要。
在 pom.xml 中使用 {范围} 标签来指定依赖的作用范围。
项目构建的生命周期
Maven 构建的生命周期描述的是一次构建构成中经历了多少个事件
总体流程:
compile -> test -> package -> install
Maven 对项目构建的生命周期划分为三种
- clean:清理工作
- pre-clean:执行一些在 clean之前完成的预先工作
- clean:一处所有上一次构建生成的文件
- post-clean:执行一些需要在 clean 之后立刻完成的工作
- default:核心工作,例如编译,测试,打包,部署等
- validate;验证
- ...
- compile:编译
- ...
- test:测试
- ...
- isntall:安装
- deploy:部署
- site:产生报告,发布站点等
插件
每一个生命周期对应的就是执行一个插件,例如 clean 就是执行 clean 对应的插件。 所有的生命周期都由插件来完成对应的功能。
聚合和继承
父模块聚合子模块 子模块继承父模块
项目分模块开发
在之前的 java 项目中,将模块下分成 Pojo,Service,Controller,Dao 等多个包,每个包都有相应的功能 在大型的 java 项目中,我们可能有多个模块,每个模块都需要使用到 Pojo,Dao 等功能,难道要在该模块下重新写 Pojo,Dao 包嘛? 可以将 Pojo,Dao 这种每个模块都会使用的包抽出来,形成一些新的模块安装到本地仓库中去,当其他的模块需要使用时可以直接在 pom.xml 中添加相应的依赖坐标即可
分模块带来的问题
将项目分成多个模块之后,当我们要构建(Compile)的时候
- 多个模块之间需要一个接着一个来构建。在存在相互依赖的情况下例如 A 依赖 B,需要先构建完成 B,在构建 A。非常的麻烦。
- 多个模块中可能有相同的依赖,例如 WebService,SearchService 模块都需要使用到 Spring,如何统一管理 Spring 依赖的版本(不能你这个模块中使用1.0.0,我这个模块中使用2.0.0,那就乱套了)
- 多个模块中有不同的依赖,例如 WebService,SearchService 需要使用 junit 做测试,但是 Pojo 模块不需要。又如何管理 junit 的版本
我们可以建立一个新的模块(父模块),这个模块没有任何的业务功能,仅作为管理模块管理其他模块(子模块)。解决上述的问题 使用父模块管理所有的模块的方式称之为:聚合
- 父模块执行构建会根据模块的依赖关系一起构建子模块
- 夫模块管理公共的依赖版本(例如:spring)
- 父工程提供并管理可选依赖,子模块根据自身的要求选择是否使用
如何建立聚合和继承的关系
- 新建一个 maven 模块起名为 parent,用以聚合需要统一管理的子模块
- 将 parent 下 pom.xml 文件的打包方式改为 pom
- 怎么说明该父模块具体管理那些个子模块呢?使用 modules 标签来指定需要管理的模块
<!-- 夫模块的 pom.xml -->
<project>
<modules>
<!-- 使用相对路径指定子模块的位置(相对于父模块的 pom.xml 文件) -->
<module>../WebService</module>
<module>../SearchService</module>
</modules>
</project>
- 所有被管理的子模块都要继承自父模块
<!-- 子模块的 pom.xml -->
<project>
<parent>
<groudId>com.lmb</groudId>
<artifactId>parent</artifactId>
<version>1.0</version>
<!-- 相对路径,指向父模块的 pom.xml -->
<relativePath>../parent/pom/xml</relativePath>
</parent>
</project>
- 父模块中的 中配置的依赖都会被子模块继承,子模块中也可以使用。
- 父模块中提供可选依赖 junit
<!-- 定义依赖管理 -->
<project>
<dependenciesManagement>
<dependencies>
<dependcy>
<groudId>junit</groudId>
<artifactId>junit</artifactId>
<version>1.0</version>
</dependcy>
</dependencies>
</dependenciesManagement>
</project>
- 子模块选择是否加载 junit,注意千万不要加,版本号已经由父模块指定
<project>
<dependencies>
<dependcy>
<groudId>junit</groudId>
<artifactId>junit</artifactId>
</dependcy>
</dependencies>
</project>
聚合和继承的区别
- 作用
- 聚合用于快速构建项目
- 继承用于快速配置
- 相同点
- 聚合通过 pom.xml 文件打包方式均为 pom,可以将两种关系制作到同一个 pom 文件中
- 聚合与继承均属于设计模块,并无实际的模块内容
- 不同点
- 聚合时当前模块中的配置关系,聚合可以感知到参与聚合的模块由哪些
- 继承时在子模块中配置关系,父模块无法感知那些子模块继承了自己
属性
- Maven 中定义属性,在 pom.xml 中 properties 中使用自定义标签来定义一个变量
<project>
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
</properties>
<!-- 引用 spring.version -->
<dependencies>
<dependcy>
<groudId>org.springframework</groudId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependcy>
</dependencies>
</project>