0、代码地址
https://gitee.com/fin_wuhongyu/bigdata2022Maven.git
1、为什么要使用Maven
1.1 Jar包添加
1. 之前添加Jar包方式
在网上找到一个Jar包,添加到libs目录下
2. 问题
之后的项目会有成百上千个Jar包,每个项目下的lib单独存在,可能会有多个Jar包被重复使用,造成磁盘空间冗余
3. 解决方式
使用本地仓库
Maven中有一个本地仓库(指电脑中的某个目录),统一存放Jar包,之后的项目只会统一依赖该目录下的Jar包,所以只会在本地仓库中保存一份
1.2 jar包获取
1. 之前获取Jar包方式
百度
csdn等论坛
官网
2. 问题
jar包不全、收费
官网需要对框架很熟悉才知道该如何下载
3. 解决方式
使用中央仓库
会有一个网址,存放规范、完整、准确,专门有人管理的jar,使用jar包的时候,直接从网上下载
1.3 jar包之间的依赖关系
1. 场景
导入Ajar包时,Ajar包依赖Bjar包,Bjar包依赖Cjar包,则使用Ajar包时,需要把A、B、Cjar包都导入,很麻烦
2.解决方式
maven导包时会将依赖的jar包一并导入,无需人工处理
1.4 jar包的冲突问题(同一个模块下的jar冲突)
1. 场景
三个工程相互依赖
MakeFriend工程依赖HelloFriend,HelloFriend依赖Hello
工程依赖的jar包
Hello工程依赖log4j.1.2.17.jar,而HelloFriend依赖log4j.1.2.14.jar
问题:使用MakeFriend工程时发生jar包冲突
该导入log4j.1.2.14.jar呢,还是log4j.1.2.17.jar?
2. 解决方式
maven会自动处理jar包冲突问题,使用最短路径者优先和先声明者优先(后续详讲)
MakeFriend工程会自动使用log4j.1.2.14.jar
1.5 将项目拆分成多个模块(不同模块下的jar冲突)
1. 场景
对于一个电商项目可能会拆分成用户模块、商品模块、购物车模块、支付模块、物流模块……来进行并行开发
每个模块所使用的log4j版本不一致,在测试时,单独测试没问题,但多个模块一起测试时,会报各种问题
2. 解决方式
将工程拆分,使用maven来进行多个模块jar包的统一管理
1.6 实现项目的分布式部署(了解)
场景
项目规模增加到一定程度,可能每个模块都需要运行在独立的服务器上(分布式部署)
这里同样需要用到Maven管理Jar包
2、Maven是什么
2.1 概述
-
自动构建工具
主要用于Java平台的项目构建和依赖管理 -
演变过程
Make→Ant→Maven→Gradle
Gradle并没有在Maven上增加多少功能
2.2 项目构建(上线)步骤
- 清洗 Clean
删除之前编译好的.class文件等代码清洗掉 - 编译 Compile
只要编译成.class文件,java代码才会被执行 - 测试 Test
可以针对项目中的关键点进行测试 - 报告
打印测试结果 - 打包 Parkage
java工程打成jar包
web工程打成war包 - 安装 Install
将jar包或者war包安装到本地仓库,提供给其他项目依赖使用 - 部署 Deploy
部署到远程仓库或者服务器上
2.3 自动化构建
指maven可以自动帮我们完成1-5、7步,不用我们一步一步去点击
3、Maven如何使用
3.1 安装与配置
3.1.1 安装maven核心程序
检查JAVA_HOME环境变量
C:\Users\111>echo %JAVA_HOME%
D:\soft\Java\jdk1.8.0_202
安装包
maven是一个免安装的软件,将安装包解压到一个非中文无空格的路径下即可使用
安装路径
D:\soft\maven\apache-maven-3.5.4
- bin
maven中的命令 - boot
引导区,使用之前要去搜索一些配置环境 - conf
配置文件,使用时候可以修改配置文件 - lib
maven开发时所使用的jar包
许可证、注意事项、说明书
给安装路径配环境变量
配置MAVEN_HOME
配置Path
检查是否配好
C:\Users\111>mvn -v
Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00)
Maven home: D:\soft\maven\apache-maven-3.5.4\bin\..
Java version: 1.8.0_202, vendor: Oracle Corporation, runtime: D:\soft\Java\jdk1.8.0_202\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
可以看到打印了maven的安装路径
Maven home: D:\soft\maven\apache-maven-3.5.4\bin\..
3.1.2 指定本地仓库
本地仓库默认位置
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
|
| Default: ${user.home}/.m2/repository
<localRepository>/path/to/local/repo</localRepository>
-->
${user.home}指默认存放在当前用户家目录下
路径:C:\Users\111.m2\repository
配置
在D:\soft\maven\apache-maven-3.5.4\conf\settings.xml中添加一行
<localRepository>D:\soft\RepMaven</localRepository>
指更改本地仓库路径到:D:\soft\RepMaven
3.1.3 更换中央仓库网址
默认:中央仓库在国外
更换成阿里云的中央仓库
配置
在D:\soft\maven\apache-maven-3.5.4\conf\settings.xml中添加
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
3.1.4 更换jdk版本
默认:maven使用jdk1.4
<profile>
<id>jdk-1.4</id>
<activation>
<jdk>1.4</jdk>
</activation>
<repositories>
<repository>
<id>jdk14</id>
<name>Repository for JDK 1.4 builds</name>
<url>http://www.myhost.com/maven/jdk14</url>
<layout>default</layout>
<snapshotPolicy>always</snapshotPolicy>
</repository>
</repositories>
</profile>
更改成和电脑一样的jdk1.8
配置
在D:\soft\maven\apache-maven-3.5.4\conf\settings.xml中添加
<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>
3.1.5 在idea中配置Maven
- 在idea登录界面进行全局配置
- 在Build,Execution,Deployment下的Build Tools中选择Maven
- 指定安装路径、配置文件和本地仓库
在Build,Execution,Deployment下的Build Tools下的Maven中选择Importing
采用默认值,如果需要下载源码或者下载速度过慢,可做调整
3.2 使用,创建第一个maven工程Hello
3.2.1 在idea中使用maven,建立maven项目
- 建一个空项目
- 配置项目名和本地路径
- 鼠标放在最下方
- 新建maven模块
- 配置本地路径和GAV
目录结构
main目录用于存放主程序
java目录用于存放源代码文件
resources目录用于存放配置文件和资源文件
test目录用于存放测试程序
3.2.2 使用test目录进行单元测试
在pom文件中导入单元测试依赖
<!--依赖-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
- 注释快捷键 ctrl+/
- alt + insert 可以快速生成依赖
编写主程序
package com.atguigu.maven;
public class Hello {
public String sayHello(String name) {
return "Hello " + name + "!";
}
}
编写测试程序
package com.atguigu;
import com.atguigu.maven.Hello;
import org.junit.Assert;
import org.junit.Test;
public class HelloTest {
@Test
public void TestHello1(){
Hello hello = new Hello();
String result = hello.sayHello("aaaa");
Assert.assertEquals("Hello aaaa!",result);
}
@Test
public void TestHello2(){
Hello hello = new Hello();
hello.sayHello("bbbb");
}
}
测试方法
- 先点击clean
- 再点击test、package、install、deploy……
结果
生成jar包
3.3 使用maven打包插件打包
maven默认打包是不带依赖的,如果需要带依赖,则需要在pom文件中加入打包插件
在pom.xml中加入如下内容
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
生成带依赖和不带依赖两种类型的jar包
4、Maven核心概念
4.1 pom.xml
maven主要通过pom文件来管理jar包
4.2 约定的目录结构
约定>配置>编码
在javaEE中,能够通过约定解决的问题就不用配置,能够通过配置解决的问题就不用编码
4.3 坐标
<?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>
<!--代码完成后打入仓库的坐标-->
<!--坐标1-->
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>1.0-SNAPSHOT</version>
<!--依赖-->
<!--怎么从仓库中找到我需要的jar包-->
<!--坐标2-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
pom文件中一般会有两个gav,第一个是为代码完成后打入仓库的坐标,第二个是怎么从本地或者中央仓库中找到我需要的jar包
gav
(1)groupId:公司或组织的域名倒序+当前项目名称
(2)artifactId:当前项目的模块名称
(3)version:当前模块的版本
坐标1
点击install,打到本地仓库路径
坐标2
jar包路径
junit jar包
- junit-4.0.jar
junit jar的pom文件 - 指定了junit jar 所依赖的jar包
junit jar的源码 - junit-4.0-sources.jar
sha1文件 - 校验核文件
D:\soft\RepMaven\junit\junit\4.0
本地仓库\groupid\artifactId\version
4.4 创建第二个工程,依赖第一个工程Hello
先将光标移动到Scratches and Consoles,再选择新建模块。
如果光标在Hello上,新生成的项目会成为Hello子模块
加上Hello和junit依赖
<?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.atguigu.maven</groupId>
<artifactId>HelloFriend</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
编写主程序
package com.atguigu.maven;
public class HelloFriend {
public String sayHelloToFriend(String name){
Hello hello = new Hello();
String str = hello.sayHello(name)+" I am "+this.getMyName();
return str;
}
public String getMyName(){
return "Idea";
}
}
不用导包,因为HelloFriend和依赖的jar包Hello都是在同一个package路径下:package com.atguigu.maven;
编写测试程序
package com.atguigu.maven;
import org.junit.Test;
import static junit.framework.Assert.*;
public class HelloFriendTest {
@Test
public void testHelloFriend(){
HelloFriend helloFriend = new HelloFriend();
String results = helloFriend.sayHelloToFriend("Maven");
System.out.println(results);
assertEquals("Hello Maven! I am Idea",results);
}
}
4.5 依赖管理
4.5.1 依赖的范围
导入jar包时,除了写jar包的gav,还要写jar包的,也就是jar包的使用范围,第二个工程HelloFriend导入Hello依赖的时候没有写,默认是compile
1)compile(默认就是这个范围)
a、src下的main目录下的Java代码可以访问这个范围的依赖
注意:这里是指main目录,而不是指main方法
b、test目录下的Java代码可以访问这个范围的依赖
c、部署到Tomcat服务器上运行时要放在WEB-INF的lib目录下
例:对Hello的依赖
主程序、测试程序和服务器运行时都需要用到
2)test
a、main目录下的Java代码不能访问这个范围的依赖
b、test目录下的Java代码可以访问这个范围的依赖
c、部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
例:对junit的依赖
只是test程序需要
3)provided
a、main目录下的Java代码可以访问这个范围的依赖
b、test目录下的Java代码可以访问这个范围的依赖
c、部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
一般用于服务器上已经存在的jar包,但是即使重复上传也不影响最终结果
例如:servlet-api在服务器上运行时,Servlet容器会提供相关API,所以部署的时候不需要
4)其他:runtime、import、system
用得少
4.5.2 依赖的传递性
Maven工程 | 依赖范围 | 对A的可见性 |
---|---|---|
A B | compile | √ |
C | test | × |
D | provided | × |
当A工程依赖于B、C、D工程时,只有B工程下的compile依赖,A工程才可以访问得到
4.5.3 依赖的原则
1)最短路径者优先
HelloFriend是MakeFriend的直接依赖,优先
2)路径相同时先声明者优先
按照MakeFriend的pom文件的顺序决定依赖先后顺序
<dependencies>
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>HelloFriend</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>OurFriends</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependencies>
会选择依赖HelloFriend的log4j.1.2.14.jar
4.5.4 依赖的排除
导入Hello依赖时,默认会把Hello中的compile依赖导入
导入Hello时需要加入exclusions排除依赖
<dependency>
<groupId>com.atguigu.maven</groupId>
<artifactId>Hello</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
4.5.5 统一管理jar包的版本
以后我们使用flink做项目时,会导入很多和flink相关的jar包,而且每个版本的flink都包含:flink-java、flink-json、flink-table-api-java-bridge_2.12,我们应该都导入同一个版本,而不是1.13的flink-java和1.14的flink-json
优化前
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>1.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-json</artifactId>
<version>1.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-java-bridge_2.12</artifactId>
<version>1.13.0</version>
</dependency>
<dependencies>
如果我们想要将这些jar包的版本统一升级为1.14,就得手动一个个修改呢,很麻烦。我们可以采取统一配置的方式:
优化后
<properties>
<flink.version>1.13.0</flink.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-json</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-table-api-java-bridge_2.12</artifactId>
<version>${flink.version}</version>
</dependency>
</dependencies>
4.5.6 仓库
4.5.6.1 分类
1)本地仓库
为当前本机电脑上的所有Maven工程服务
2)远程仓库
a)私服
架设在当前局域网环境下,为当前局域网范围内的所有Maven工程服务
b)中央仓库
架设在Internet上,为全世界所有Maven工程服务
c)中央仓库的镜像
为中央仓库分担流量,减轻中央仓库的压力
例如:阿里和网易
4.5.6.2 仓库中的文件
(1)Maven的插件
(2)我们自己开发的项目的模块
(3)第三方框架或工具的jar包
不管是什么样的jar包,在仓库中都是按照坐标生成目录结构,所以可以通过统一的方式查询或依赖
4.5.7 生命周期
1)Clean Lifecycle(重点)
- 概念
移除上一次构建生成的文件
2)Default Lifecycle(重点)
- 概念
构建核心工作
生命周期内,运行任意一个生命周期,前面的生命周期都会被运行
默认生命周期
- 验证
核心1:validate - 资源处理
generate-sources
process-sources
generate-resources
process-resources - 编译项目的源代码
核心2:compile - 测试资源处理
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources - 编译项目的源代码
test-compile - 测试
process-test-classes
核心3:test - 接受编译好的代码,打包成可发布的格式,如JAR
prepare-package
核心4:package - 安装资源
pre-integration-test
integration-test
post-integration-test
verify - 将包安装至本地仓库,以让其它项目依赖
核心5:install - 将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行
核心6:deploy
3)Site Lifecycle
- 概念
生成项目报告、站点、发布站点
5、继承
5.1 为什么需要继承
之前讲依赖的传递时,说只有compile的依赖是可以被传递的,但如果是scope为test的依赖呢,我们如果想在子父模块中统一管理,则需要继承来实现
例子:有三个模块,Hello、HelloFriend、MakeFriend中,都有scope为test的依赖junit,但版本各不相同,怎么统一成4.9的版本呢
Hello
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
HelloFriend
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
MakeFriend
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
解决思路:我们需要使用继承机制,将各个依赖信息统一提取到父工程Parent去管理三个子模块Hello、HelloFriend、MakeFriend,而不是一个个单独手工修改
5.2. 创建父工程Parent
a、 子父模块GroupId一致
b、声明打包方式,为pom
含义
只做项目管理,不写任何代码
pom.xml
<packaging>pom</packaging>
之前不写packaging指打包的时候,默认打jar包
jar
如果是web工程,要改成war
<packaging>war</packaging>
c、 在子工程中引用父工程
<!--继承-->
<parent>
<groupId>com.atguigu.maven</groupId>
<artifactId>Parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
<relativePath>../Parent/pom.xml</relativePath>
</parent>
…/Parent/pom.xml指返回上级,并进入Parent文件夹中找到pom文件
d、 在父工程中管理依赖
<!--依赖管理-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
e、 子项目中重新定义依赖
删除版本号和范围,因为在父工程中已经定义过了
在子项目中重新指定需要的依赖,删除范围和版本号
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
f、结果
6、聚合
6.1. 为什么需要聚合
当模块较多,我们每次修改代码时,都需要先把修改的模块的代码clean、install一次,然后该模块的被依赖依赖代码也需要clean和install,很麻烦
6.2. 如何配置聚合
父模块的pom文件添加
<!--聚合-->
<modules>
<module>../MakeFriend</module>
<module>../HelloFriend</module>
<module>../Hello</module>
</modules>
添加后,Parent会显示root
6.3 如何使用聚合
- 在父工程中点击clean
三个target同时被删除
- 在父工程中点击package
同时生成三个target
之后可以使用父工程一起clean、test、install、package……
7、Maven酷站
7.1 查询GAV
通过给定jar包的名字,版本,查询gav
7.2 使用
网址:http://mvnrepository.com/
一般情况选择使用人数最多的jar包
一般情况选择使用人数最多的版本
复制gav
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>