Maven
一.Maven概述
1.1通过六个案例学习Maven的九个概念
第一个Maven项目 (手动创建Java项目) 不使用idea
第二个Maven工程(IDEA中创建Java项目)
第三个Maven项目(创建Web项目)
第四个Maven工程(依赖管理)
第五个Maven工程(继承)
第六个Maven工程(聚合)
1.2Maven项目的三种关系
依赖、继承、聚合
1.3 Maven的九个概念
① 仓库管理
② POM
① 约定的目录结构
② 坐标
③ 依赖管理
⑥ 生命周期
⑦ 插件和目标
⑧ 继承
⑨ 聚合
★二. Why
2.1 添加第三方jar包
2.2jar包之间的依赖关系
2.3 处理jar包之间的冲突
2.4 获取第三方jar包
使用了Maven之后,使用Maven我们可以享受到一个完全统一规范的jar包管理体系,直接从官方仓库(通过唯一的坐标)查找下载
2.5将项目拆分成多个工程模块
① 需要用到Maven的依赖管理机制。
②上层模块依赖下层,所以下层模块中定义的API都可以为上层所调用和访问。
2.6 实现项目的分布式部署
在实际生产环境中,项目规模增加到一定程度后,可能==每个模块都需要运行在独立的服务器上,我们称之为分布式部署==,这里同样需要用到Maven。
三. What
3.1自动化构建工具
构建的步骤可以使用Maven全自动搞定,减轻了开发者的负担
★★3.2Maven的核心概念
① 仓库管理
② POM
③ 约定的目录结构
④ 坐标
⑤ 依赖管理
⑥ 生命周期
⑦ 插件和目标
⑧ 继承
⑨ 聚合
★四 Maven 仓库
4.1仓库分类
①本地仓库:
Maven在本地存储构件的地方,对应一个文件夹。为当前本机电脑上的所有Maven工程服务。
②远程仓库
(1)中央仓库:Maven官方维护的仓库,最权威的仓库。中央仓库就是一个默认的远程仓库。
(2)镜像仓库:为了减轻中央仓库负担,同时更快的响应用户请求,国内外有能力的组织搭建的仓库, 这个仓库就是将中央仓库中的所有内容复制了一份存起来。比如阿里Maven镜像。
(3)私服:一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。使用私服可以节省自己的外网带宽,提高构建速度,提高稳定性,降低中央仓库的负荷;甚至有些构件无法从外部仓库获得的时候,我们可以把这些构件部署到内部仓库(私服)中,供内部maven项目使用。
③Maven仓库的总体结构
如图所示:
私服是远程仓库
如果不指定,远程仓库会默认访问中央仓库
4.2访问仓库的步骤:
访问仓库:本地仓库----远程仓库(私服—镜像或者中央仓库,看指定)
如果本地仓库和远程仓库都没有需要的构件,Maven就会报错。
五.安装Maven
5.1检查JDK安装是否正确
访问环境变量,需要使用两个%括起来
要安装Maven,必须先安装JDK
5.2下载Maven
官网地址:https://maven.apache.org/。进入Maven官网,选择Download下载页面
5.3解压安装
安装源文件夹和目的文件夹尽量不要有中文、空格等特殊字符;有些同学的计算机名就是中文,比如张三丰。建议修改.
5.4 配置环境变量。
DK的环境变量 JAVA_HOME PATH
Tomcat的环境变量 CATALINA_HOME PATH
Maven的环境变量 M2_HOME(不是MAVEN_HOME) PATH
新建系统变量
编辑系统变量 path
%M2_HOME%\bin或D:\Java\apache-maven-3.6.0\bin
5.5查看Maven版本信息验证安装是否正确
5.6配置本地仓库
(可选,如果不配置,有默认的本地库位置)
[1]Maven默认的本地仓库:.m2\repository目录。表示当前用户的家目录。
[2]Maven的核心配置文件位置:
%M2_HOME%\conf\settings.xml
[3]设置方式
<localRepository>D:/repository</localRepository>
5.7配置阿里镜像服务器地址(可选)
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
5.8配置JDK版本和编码
(可选 全局配置,如果不配置,可以在项目中进行局部配置)
该配置为MAVEN中JDK版本和编码的全局配置,影响当前主机创建的所有MAVEN项目。此配置为可选,建议配置。
<profiles>
<!--指定JDK版本 -->
<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>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
</profile>
</profiles>
六. Maven目录结构
现在JavaEE开发领域普遍认同一个观点:约定>配置>编码。意思就是能用配置解决的问题就不编码,能基于约定的就不进行配置。而Maven正是因为指定了特定文件保存的目录才能够对我们的Java工程进行自动化构建。
测试的代码(使用Junit进行测试)必须写到test下
pom.xml是Maven项目的管理中心
target目录,编译后.class文件和resources的存储位置
src/main/java:存放项目的java类源文件,即:Xxx.java
src/main/resources:存放项目的资源文件,如.xml、.properties
src/test/java:存放项目的用于测试的java类源文件,即:XxxTest.java
src/test/resources:存放项目的测试相关的资源文件,如.xml、.properties
pom.xml:Maven项目的配置文件,是学习Maven的重点
target:编译之后的结果,比如class、资源文件
七. 第一个Maven项目 (手动创建)
八 第二个Maven工程(IDEA中创建Java项目)
如果弹出Maven project need to be import,是提示Maven项目需要导入变化,选择Import Changes即可。一般不选择Enable Auto-Import。
●第一步:创建约定的目录结构
●第二步:pom.xml
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.maven</groupId>
<artifactId>_02_maven_java</artifactId>
<version>1.0-SNAPSHOT</version>
<!--项目类型,默认jar -->
<!-- <packaging>jar</packaging>-->
<dependencies>
<!-- JUnit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
●第三步:开发业务代码(main)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String userId;
private String realName;
private Integer age; //阿里开发规范中明确表示,不要使用基本数据类型修饰成员变量 Integer null
private String address;
●第四步:开发测试代码(test)
public class TestUser {
@Test
public void testUser(){
User user = new User();
System.out.println(user);
//如果没有安装插件,该语句会报错,但是不影响运行
User user2 = new User("zhangsan","张三",20,"北京市");
System.out.println(user2);
}
}
●第五步:使用Maven进行构建
★九 POM
POM( Project Object Model,项目对象模型) 是Maven项目的基本工作单元,是一个XML文件,位于项目根目录,包含了项目基本信息,用于描述项目如何构建,声明项目依赖等。**Maven工程的核心配置
-
可以说学习Maven就是学习pom.xml文件中的配置。
- 根元素是project
modelVersion:设置POM模型的版本。它必须匹配您使用的Maven版本。版本4.0.0匹配Maven版本2和3。
★十 坐标
10.1 aven的坐标
Maven的坐标元素包括groupId、artifactId、version、packaging、classfier等,其中groupId、artifactId、version是必须定义的,即可唯一的标记一个坐标,称为坐标三要素,简称GAV。
[1]groupId:公司或组织的域名倒序+当前项目名称
[2]artifactId:当前项目的模块名称
[3]version:当前模块的版本
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
10.2如何通过坐标到仓库中查找jar包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
org/projectlombok/lombok/1.18.12/lombok-1.18.12.jar
<groupId>com.atguigu.maven</groupId>
<artifactId>_02_maven_java</artifactId>
<version>1.0-SNAPSHOT</version>
com/atguigu/maven/_02_maven_java/1.0-SNAPSHOT/_02_maven_java-1.0-SNAPSHOT.jar
十一第三个Maven项目(创建Web项目 略)
★十二、 生命周期
●Maven有三套相互独立的生命周期,分别是
①Clean Lifecycle在进行真正的构建之前进行一些清理工作。
②Default Lifecycle构建的核心部分,编译,测试,打包,安装,部署等等。**
③Site Lifecycle生成项目报告,站点,发布站点。
再次强调一下它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site 运行所有这三套生命周期。
每个生命周期又包含了多个阶段。这些阶段在执行的时候是有固定顺序的。后面的阶段一定要等前面的阶段执行完成后才能被执行。
十三. 插件
★ Maven的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成
每个生命周期中都包含着一系列的阶段(phase)。这些 phase 就相当于 Maven 提供
² 的统一的接口,然后这些 phase 的实现由 Maven 的插件来完成。
q Maven插件列表的官网页面:http://maven.apache.org/plugins/
q Maven插件的下载位置:本地仓库\org\apache\maven\plugins
² maven-clean-plugin、maven-compile-plugin属于Maven官方插件,命名规则为maven-xxx-plugin。
tomcat7-maven-plugin属于第三方插件,命名规则为xxxx-maven-plugin。
★十四. 依赖
1. 依赖的范围
Maven项目之间的关系:依赖关系、继承关系、聚合关系
依赖关系是并列关系(朋友关系) 继承和聚合是上下级关系(父子关系)
编译 | 测试 | 运行(部署访问) | 示例 | |
---|---|---|---|---|
Compile(编译) | √ | √ | √ | jstl.jarlog4j.jar |
Provided() | √ | √ | × | servlet.jarjsp.jarlombok.jar |
test | × | √ | × | junit |
system | 和provided类似,但是不常用 | |||
runtime | × | √ | √ | JDBC的驱动 |
import | 讲解SpringBoot的时候进行重点说明 |
2.依赖传递性
当存在间接依赖的情况时,主工程对间接依赖的jar可以访问吗?这要看间接依赖的jar包引入时的依赖范围——**只有依赖范围为compile时可以访问。例如
Maven工程 | 依赖范围 | 对A的可见性 | ||
---|---|---|---|---|
A | B | C | compile | √ |
D | test | × | ||
E | provided | × |
jar冲突的情况
①路径最短者优先
②路径相同时先声明者优先
问题:moduleA先声明moduleB,但是想使用moduleD的jar,可以吗?
可以使用排除(exclusion!!)
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>_04_moduleD</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<!--排除指定的依赖,只需要指定groupId和artfactId -->
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
十五 统一管理jar版本
<properties>
<spring-version>5.3.3</spring-version>
<module-version>1.0-SNAPSHOT</module-version>
<mysql-version>8.0.16</mysql-version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
★十六 继承
为什么需要继承
由于非compile范围的依赖信息是不能在“依赖链”中传递的,所以有需要的工程只能单独配置。
解决方案:使用继承可以解决:父项目中的jar,不管是compile,还是test、providied等,子项目都可以直接引用(父子关系还是比朋友关系靠谱)
注意:
①. 父项目和子项目在关系上是父子关系,在创建项目时是并列关系
②. 父项目必须是pom类型
只需要子项目通过parent标签指定父项目,单向联系
<parent>
<groupId>com.atguigu.maven</groupId>
<artifactId>_05_maven_father</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
③. 父项目中的jar,不管是compile,还是test、providied等,子项目都可以直接引用
④. 子项目只能从父项目继承资源,不能继承父项目定义的源代码。
⑤. 父项目必须是pom项目,是用来提供资源让子项目来继承的,不是用来开发源代码。所以pom项目的src目录可以直接删除。
⑥. 父项目如果采用dependencies元素,表示其中所有的jar都是父项目所具有的,并且子项目会自动的继承。
父项目如果采用dependencyManagement元素,表示其中所有的jar并不是父项目所具有的,只是一个声明,子项目不会自动的继承。如果需要哪些,就手动的引入哪些即可。
子项目引入时只需要指定groupId和artfactId。如果版本不同,才需要使用version。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
⑦. 父项目和子项目必须单独的编译、测试、部署。因为是并列的关系,并不是一个大项目包括多个模块
⑧. 如果父项目打成jar包并上传到本地库,子项目可以直接使用;如果父项目没有打成jar包并上传到本地库,子项目如何要正确的使用父项目,必须配置relativePath。
<parent>
<groupId>com.atguigu.maven</groupId>
<artifactId>_05_maven_father</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父项目的pom.xml的相对路径,默认值是pom.xml-->
<relativePath>../_05_maven_father/pom.xml</relativePath>
</parent>
★★★十七 聚合
实际开发中继承使用的并不多,为什么?
①. 父项目和子项目必须单独的编译、测试、部署。因为是并列的关系,并不是一个大项目包括多个模块
② 如果父项目打成jar包并上传到本地库,子项目可以直接使用;如果父项目没有打成jar包并上传到本地库,子项目如何要正确的使用父项目,必须配置relativePath。
解决方案:聚合
继承是并列的多个项目;但是聚合是1个父项目下面有多个子项目,整体上是一个项目。只要对父项目进行编译、测试、部署等操作,就会对所有的子项目进行编译、测试、部署等操作。
举例:商场myshopping,包括order、payment、product等多个模块,是一个项目,非常适合使用聚合。
注意:
①. 聚合关系首先是继承关系;父项目必须是pom,src也可以删掉
②. 聚合关系是一种双向关系
<groupId>com.atguigu.maven</groupId>
<artifactId>_06_myshopping</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>order</module>
<module>payment</module>
<module>product</module>
</modules>
<parent>
<artifactId>_06_myshopping</artifactId>
<groupId>com.atguigu.maven</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>product</artifactId>
③. 子项目只要指定artifactId****,不需要重复指定****groupId和version
④只要对父项目进行编译、测试、部署等操作,就会对所有的子项目进行编译、测试、部署等操作。
★简答题:Maven中依赖、继承、聚合的区别
①关系上的区别:依赖:朋友关系,继承和聚合是父子关系(继承是单向,聚合是双向的)
②范围上的区别:
依赖:引入时的依赖范围——只有依赖范围为compile时可以访问
继承:父项目中的jar,不管是compile,还是test、providied等,子项目都可以直接引用(父子关系还是比朋友关系靠谱)
③模块的区别:
继承:因为是并列的关系,并不是一个大项目包括多个模块
聚合:继承是并列的多个项目;但是聚合是1个父项目下面有多个子项目,整体上是一个项目。
③操作的区别:
继承:父项目和子项目必须单独的编译、测试、部署。
聚合:对父项目进行编译、测试、部署等操作,就会对所有的子项目进行编译、测试、部署等操作。
shopping
com.atguigu.maven
1.0-SNAPSHOT
4.0.0
product
**③**. 子项目只要指定**artifactId****,不需要重复指定****groupId和version**
**④**只要对父项目进行编译、测试、部署等操作,就会对所有的子项目进行编译、测试、部署等操作。
### ★简答题:Maven中依赖、继承、聚合的区别
①关系上的区别:依赖:朋友关系,继承和聚合是父子关系(继承是单向,聚合是双向的)
②范围上的区别:
依赖:引入时的依赖范围——**只有依赖范围为compile时可以访问**
继承:父项目中的jar,不管是compile,还是test、providied等,子项目都可以直接引用(父子关系还是比朋友关系靠谱)
③模块的区别:
继承:因为是并列的关系,并不是一个大项目包括多个模块
聚合:继承是并列的多个项目;但是聚合是1个父项目下面有多个子项目,整体上是一个项目。
③操作的区别:
继承:父项目和子项目必须单独的编译、测试、部署。
聚合:对父项目进行编译、测试、部署等操作,就会对所有的子项目进行编译、测试、部署等操作。