My Maven notes
# Maven 简介
# Maven 的需求
目前技术在开发中存在的问题
- 一个项目就是一个工程
如果项目非常庞大,就不适合继续使用 package 来划分模块。最好是每一个模块对应一 个工程,利于分工协作。
借助于 Maven 就可以将一个项目拆分成多个工程。
- 项目中的 jar 包必须手动 “复制”、“粘贴” 到 WEB-INF/lib 目录下
带来的问题是:同样的 jar 包文件重复出现在不同的项目工程中,一方面浪费存储空间,另外也让工程比较臃肿。
借助 Maven , 可以将 jar 包仅仅保存在 “仓库” 中,有需要使用的工程 " 引用” 这个文件接口,并钚需要真的把 jar 包复制过来。
- jar 包需要别人替我们准备好,或到官网下载
不同技术的官网提供 jar 包下载的形式是五花八门的。
有些技术的官网就是通过 Maven 或 SVN 等专门的工具来提供下载的。
如果是以不规范的方式下载的 jar 包,那么其中的内容很可能也是不规范的。
借助于 Maven 可以以一种规范的方式下载 jar 包。因为所有知名框架或第三方工具的 jar 包以及按照统一 - 的规范存放在 了 Maven 的中央仓库中
以规范的方式下载的 jar 包,内容也是可靠的。
Tips: "统一的规范" 不仅是对 T 开发领域非常重要,对于整个人类社会都是非常重要的。
- 一个 jar 包依赖的其他 jar 包需要自己手动加入到项目中
FileUpload 组件–>IO 组件。 commons-fileupload-1.3.jar 依赖于 commons-io-2.0.1jar
如果所有 jar 包之间的依赖关系都需要程序员自己非常清楚的了解,那么就会极大的增加学习成本。
Maven 会自动将被依赖的 jar 包导入进来。
# Maven 的概述
Maven 是 Apache 软件基金会组织维护的一款自动化构建工具。主要有两个作用:
- maven 工程对 jar 包的管理过程
- 项目的一键构建
# 构建
概念:以 “java 原文件”、“框架配置文件”、“JSP”、“HTML”、“图片” 等资源为 “原材料”,去 “生产” 一个可以运行的项目过程
其中包括:编译、部署、搭建
-
编译:Java 源文件 [User.java]-→ 编译 - +Class 字节码文件 [User.class]- + 交给 JVM 去执行
-
部署:一个 BS 项目最终运行的并不是动态 Web 工程本身,而是这个动态 Web 工程 " 编译的结果”
一个形象的比喻:生的鸡 -> 处理 -> 熟的鸡
动态 Web 工程 -> 编译、部署 -> 编译结果
图解编译结果与动态 Web 工程的区别:
开发过程中,所有的路径或配置文件中配置的类路径等都是以编译结果的目录结构为标准的
其中:
被称为运行时环境,并不会加载到编译结果中
-
构建过程的各个环节
- 清理:将以前编译得到的旧的 class 字节码文件删除,为下一 - 次编译做准备
- 编译:将 Java 源程序编程成 class 字节码文件
- 测试:自动测试,自动调用 junit 程序
- 报告:测试程序执行的结果
- 打包:动态 Web_ I 程打 war 包,Java 工程打 jar 包
- 安装: Maven 特定的概念一将打包得到的文件复制到 " 仓库” 中的指定位置
- 部署:将动态 Web. 工程生成的 war 包复制到 Servlet 容器的指定目录下,使其可以运行
-
自动化构建
# 安装 Maven 核心程序
- 检查 JAVA_HOME 环境变量,maven 本身就是 java 写的,所以要求必须安装 JDK
-
下载并解压 maven 安装程序,放在一个非中文无空格路径下
-
配置 Maven 相关的环境变量
-
验证是否安装成功,在 cmd 中运行 mvn -v 命令
# 第一个 Maven 工程(原生 Maven)
- 创建约定的目录结构
目录结构
Hello 工程名
|---src 源码
|---|---main 放主程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---|---test 存放测试程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---pom.xml Maven的核心配置文件
手动创建时为什么要遵守约定的目录结构?
Maven 要负责我们这个项目的自动化构建,以编译为例,Maven 要想自动进行编译,那么它必须知道 Java 源文件保存在哪里
而,我们自定义的东西要想让框架知道或工具知道,有两种方式
- 通过配置的方式告诉框架
- 按照框架约定的来创建
- 编写 pom.xml
<?xml version="1.0" ?>
<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>
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Hello</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 在 src/main/java/com/atguigu/maven 目录下新建文件 Hello.java
package com.atguigu.maven;
public class Hello {
public String sayHello(String name){
return "Hello "+name+"!";
}
}
- 在 /src/test/java/com/atguigu/maven 目录下新建测试文件 HelloTest.java
package com.atguigu.maven;
import org.junit.Test;
import static junit.framework.Assert.*;
public class HelloTest {
@Test
public void testHello(){
Hello hello = new Hello();
String results = hello.sayHello("litingwei");
assertEquals("Hello litingwei!",results);
}
}
- 在命令行中运行基本命令
mvn compile 编译
mvn clean 清理
mvn test 测试
mvn package 打包
注意:运行 Maven 命令时一定要进入 pom.xml 文件所在的目录!
# Maven 的核心概念
# Maven 目录结构
目录结构
Hello 工程名
|---src 源码
|---|---main 放主程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---|---test 存放测试程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---pom.xml Maven的核心配置文件
# Maven 常用命令
- mvn clean:将 target 目录删除,但是已经 install 到仓库里的包不会删除
- mvn compile:编译主程序
- mvn test-compile:编译测试程序
- mvn test:执行测试
- mvn package:打包
- mvn install:安装
- mvn deploy:部署、生成站点
# maven 工程对 jar 包的管理过程
- ①Maven 的核心程序中仅仅定义了抽象的生命周期,但是具体的工作必须由特定的插件来完成。而插件本身并不包含在 Maven 的核心程序中。
- ② 当我们执行的 Maven 命令需要用到某些插件时,Maven 核心程序会首先到本地仓库中查找。
- ③ 本地仓库的默认位置: C:\USERS\USERNAME
\
.m2\repository - ④Maven 核心程序如果在本地仓库中找不到需要的插件,那么它会自动连接外网,到中央仓库下载
- ⑤ 如果此时无法连接外网,则构建失败。
- ⑥ 修改默认本地仓库的位置可以让 Maven 核心程序到我们事先准备好的目录下查找插件
- [1] 找到 Maven 解压目录 \confsettings.xml
- [2] 在 settings.xm | 文件中找到 localRepository 标签
- [3] 将
<localRepository>
/path/to/local/repo</localRepository
> 从注释中取出 - [4] 将标签体内容修改为已经准备好的 Maven 仓库目录
# POM
Project Object Model 项目对象模型
DOM Document Object Model 文档对象模型
pom.xml 对于 Maven 工程是核心配置文件,与构建过程相关的一切设置都在这个文件中进行配置。重要程度相当于 web.xm | 对于动态 Web 工程
# 坐标 gav
-
数学中的坐标:
- 在平面上,使用 x、y 两个向量可以唯一的定位平面中的任何一个点
- 在空间上,使用 x、y、z 三个向量可以唯一的定位空间中的任何一个点
-
Maven 的坐标
-
使用三个向量在仓库中唯一定位一个 Maven 工程
- groupid:公司或组织域名的倒序 + 项目名
com.baidu.projectname
- artifactid:模块名
- version:版本
-
Maven 工程的坐标与仓库中路径的对应关系
<groupId> org.springframework </groupId> <artifactId> spring-core </artifactId> <version>4.0.0.RELEASE </version>
org/springframework/spring-core/4.0.0.RELEASE/spring-core-4.0.0.RELEASE.jar
# 仓库 repository
-
-
仓库的分类
-
本地仓库:当前电脑上部署的仓库目录,为当前电脑上多有 Maven 工程服务
-
远程仓库
- 私服:搭建在局域网环境中,为局域网范围内的所有 Maven 工程服务
- 中央仓库:架设在 Internet 上,为全世界所有 Maven 工程服务
- 中央仓库镜像:为了分担中央仓库的流量,提升用户访问速度
-
-
仓库中保存的内容:Maven 工程
- Maven 自身所需的插件
- 第三方框架或工具的 jar 包
- 自己开发的 Maven 工程
# 依赖【初步】
-
Maven 解析依赖信息时会到本地仓库中查找被依赖的 jar 包。对于我们自己开发的 Maven 工程,使用 mvn install 命令安装后就可以进入仓库。
-
依赖的范围
- compile 范围依赖
- 对主程序是否有效:有效
- 对测试程序是否有效:有效
- 是否参与打包:参与
- 是否参与部署:参与
- 典型例子:spring-core
- test 范围依赖
- 对主程序是否有效:无效
- 对测试程序是否有效:有效
- 是否参与打包:不参与
- 是否参与部署:不参与
- 典型例子:junit
- provided 范围依赖
- 对主程序是否有效:有效
- 对测试程序是否有效:有效
- 是否参与打包:不参与
- 是否参与部署:不参与
- 典型例子:servlet-api.jar
- compile 范围依赖
# 生命周期
- 各个构建环节执行的顺序:不能打乱顺序,必须按照既定的正确顺序来执行
- Maven 的核心程序中定义了抽象的生命周期,生命周期中各个阶段的具体任务是由插件来完成的
- Maven 核心程序为了更好的实现自动化构建,按照这一的特点执行生命周期中的各个阶段:不论现在要执行生命周期中的哪一个阶段,都是从这个生命周期最初的位置开始执行
例如:
# 插件与目标
- 生命周期的各个阶段仅仅定义了要执行的任务是什么
- 各个阶段和插件的目标是对应的
- 相似的日标由特定的插件来完成
- 可以将目标看作” 调用插件功能的命令 “
# 依赖【高级】
- 依赖的传递性
好处:可以传递的依赖不必在每个模块工程中都重复声明,在” 最下面” 的工程中依赖 - 次即可。
注意:非 compile 范围的依赖不能传递。所以在各个工程模块中,如果有需要就得重复声明依赖。
-
依赖的排除
-
需要设置依赖排除的场合
-
依赖排除的设置方式
<exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions>
-
-
依赖的原则
-
作用:解决模块工程之间的 jar 包冲突问题
-
情景设定一:验证路径最短者优先原则
-
情景设定二:验证路径相同时先声明者优先
-
-
统一管理依赖的版本
- 情景举例
这里需要对 spring 各个 jar 包的依赖版本进行管理,如需要升级到 4.1.1
-
配置方式
- 使用 properties 标签内使用自定义标签统一声明版本号
<properties> <cvzhanshi.spring.version>4.0.0.RELEASE</cvzhanshi.spring.version> </properties>
- 在需要统一版本的位置,使用 ${自定义标签名} 引用声明的版本号
<version>${cvzhanshi.spring.versio}</version>
-
其实 properties 标签配合自定义标签声明数据的配置并不是只能用于声明依赖的版本号。凡是需要统一声明后再弓 | 用的场合都可以使用
<properties> <cvzhanshi.spring.version>4.0.0.RELEASE</cvzhanshi.spring.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
- 情景举例
# 继承
-
现状
-
需求:统一管理各个模块工程中对 junit 依赖的版本
-
解决思路:将 junit 依赖统一提取到 “父” 工程中,在子工程中声明 junit 依赖时不指定版本,以父工程中统一设定的为准。同时也便于修改
-
操作步骤
- 创建一个 Maven 工程作为父工程。注意:打包的方式为 pom
<groupId>com.cvzhanshi.maven</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging>
- 在子工程中声明对父工程的引用
<!-- 子工程中声明父工程 --> <parent> <groupId>com.cvzhanshi.maven</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 以当前文件为基准的父工程pom.xml文件的相对路径 --> <relativePath>../Parent/pom.xml</relativePath> </parent>
-
将子工程的坐标中与父工程坐标中重复的内容删除
-
在父工程中统一管理 junit 的依赖
<!-- 配置依赖的管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement>
- 在子工程中删除 junit 依赖的版本号部分
-
注意:配置继承后,执行安装命令时要先安装父工程
# 聚合
- 作用:一键安装各个模块工程
- 配置方式:在一个” 总的聚合工程 “中配置各个参与聚合的模块
<!-- 配置聚合 -->
<modules>
<!-- 指定各个子工程的相对路径 -->
<module>../HelloFriend</module>
<module>../MakeFriends</module>
<module>../Hello</module>
</modules>
- 使用方式:在聚合工程的 pom.xml 上点右键 ->run as->maven install(eclipse 中)
# IDEA 中使用 Maven
# 在 Idea 中配置 Maven
Idea 中也自带 Maven 插件,而且我们也可以给自带的 Maven 插件进行配置, 所以我们可以使用自带的 Maven,也可以使用我们安装的 Maven 核心程序
# 配置自己安装的 Maven
# 配置 IDEA 自带的 Maven 插件
进入 idea 的安装目录
E:\study\Java\soft\idea\ideaIU-2019.2.4.win\plugins\maven\lib\maven3\conf 配置 setting.xml
1、添加本地仓库位置
<localRepository>E:\study\Java\maven\apache-maven-3.5.3\repository</localRepository>
2、添加阿里云仓库和中央仓库,方便联网时下载 jar 包
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
<!-- 中央仓库1 -->
<mirror>
<id>repo1</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo1.maven.org/maven2/</url>
</mirror>
<!-- 中央仓库2 -->
<mirror>
<id>repo2</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://repo2.maven.org/maven2/</url>
</mirror>
3、配置 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>
</properties>
</profile>
# 使用 Maven 创建 Java 工程
# 创建
# 测试
- 配置 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>
<groupId>com.cvzhanshi.maven</groupId>
<artifactId>Hello</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 在 src/main/java 目录下创建包并创建 Hello.java 文件
/**
* @author cVzhanshi
* @create 2021-04-26 1:06
*/
public class Hello {
public String sayHello(String name){
return "Hello "+name+"!";
}
}
- 在 /src/test/java 目录下创建包并创建 HelloTest.java 文件
package com.atguigu.maven;
import org.junit.Test;
public class HelloTest {
@Test
public void testHello(){
Hello hello = new Hello();
String maven = hello.sayHello("Maven");
System.out.println(maven);
}
}
使用 Maven 的方式运行 Maven 工程 :
# 使用 Maven 创建 Java Web 工程
# 创建
-
选择 Maven-> 选择 java jdk-> 勾选 Create from archetype-> 选择 maven-archetype-webapp
-
填写 GroupId(域名。公司名。项目名)、Artifacted (模块名)
-
选择本地 maven 解压的路径、配置文件
-
选择工作空间
-
创建成功,结构如下
-
在 main 底下 new 两个 Directory:java,resources
-
点 Project Struct,设置源码文件夹和资源文件夹
-
tomcat 部署
- 启动 tomcat
# Idea 中导入 Maven 项目
-
点击 Project Structure
-
点击 Modules→➕→Import Module
-
找到项目所在的位置
-
选择 Import module from external model(从外部模型导入模块)→Maven →Finish