大数据之路week05--day02(Maven安装,环境变量的配置及基本使用)
今天我们就来学习一下maven,怎么说呢,maven更像是一种管理的工具,实现的原理是使用插件。
举个例子,比如说,一个公司需要做一个项目,这个项目又分成了很多的模块,每个模块又分成了许多的业务等等,这些需要许许多多的小组进行进行,最后再进行整合。
那么,就有一个很大的问题,IT技术发展这么快的时代里,每个人使用的jar包版本,使用的软件版本,等等,如果不一样的话,就算单个小模块可以进行,一旦整合就会出现各种各样的问题,那么如何避免或者说,尽量的最大程度上减少这种情况发生呢?
那就要用到Maven了,它更像是每一个开发者从网上的一个中央仓库中获取到开发锁指定需要的jar包,并且也可以把自己完成的项目打包成一个jar包发布到这个中央仓库中,供其他的模块开发人员使用,同时,项目经理等管理员,可以统一开发所需要的版本,最大程度上减少这种非技术问题的情况发生。
那么,接下来就开始学者怎么使用它吧!!
一、安装并配置maven环境
我这里提供了百度云链接,可以自行下载:
链接:https://pan.baidu.com/s/1mE8k22lwUQJAd-GbQ3zzAg
提取码:twj0
下载到自定义路径即可:我这里下载到的是D盘:
到这里,我们的maven就算是下载好了。接下来是配置环境变量
怎么打开环境变量配置的界面,可以参考怎么安装jdk https://www.cnblogs.com/wyh-study/p/11794205.html (当然这里配置maven的前提是安装并配置了JDK)
新建
接着,去path中添加配置bin目录
接着,我们一路确定就可以了。
我们用cmd命令行输入mvn -v看看有没有配置成功:(看到如下的界面就说明配置成功了)
接着,距离我们开始进行代码又近了一步,还有一步工作没有做:那就是修改下载的路径,为什么要改呢?
这么说吧,因为这个中央仓库是国外的 (https://mvnrepository.com/ 这个网址是国外的,如果我们要通过编译器来访问的话,下载速度会非常的慢。。。你们懂的那种还不能做什么事那种就最难受。。)
所以,我们中国国内,阿里云就把国外这个中央仓库复制了一份,国外更新,我们也更新,我们国内直接访问阿里云进行下载,就会快很多。
因此,我们需要修改下载的路径,怎么修改呢?
我们打开之前下载的maven文件:找到settings.xml文件,编辑打开:
1 <mirror> 2 <id>alimaven</id> 3 <mirrorOf>*</mirrorOf> 4 <url>https://maven.aliyun.com/repository/central</url> 5 </mirror> 6 </mirrors>
接着,我们虽然将下载的路径换了,但是我们并没有指定本地的下载到我们自己电脑的路径:
1、我先自定义创建目录,把它当作我后面下载jar包的目标路径
2、接着我们修改刚刚打开的settings.xml (这里就不给出代码了,每个人的自定义目录可能不一样)
二、然后,我们打开myeclipse:
1、
2、
3、
4、
到此,我们myeclipse就配置好了。
三、 maven项目的目录结构
先在这里插入一点个人对maven的理解,我们之前每个项目都需要有自己的jar包,但是这么多jar包很多有相同的,而这些jar包又是基于项目存放的,如果我们跨越项目这一层,统一管理jar包呢, 这样不就可以节约很多空间和时间。所以,我们使用maven工具来支配之,那么我们maven存放jar包的地方就是我们说的仓库,
当我们在第一步设置好maven的环境之后,默认就在c盘的user目录下的.m2文件夹充当仓库。
a
maven在每台机器上创建一个本机仓库,把本机上所有maven项目依赖的jar包统一管理起来,而且这些jar包用“坐标”来唯一标识(注:坐标是另一个重要的概念,后面还会讲到,这里只要简单理解成“唯一识别某个jar包文件名、版本号”的标识即可),这样所有maven项目就不需要再象以前那样把jar包复制到lib目录中,整个maven项目看起来十分清爽。
扯了很多,现在说下maven项目的目录结构是怎样的 :
诶,这些有些怎么标红呢? 是因为我们使用maven约定由于配置。src/main/java约定用于存放源代码,src/main/test用于存放单元测试代码,src/target用于存放编译、打包后的输出文件。这是全世界maven项目的通用约定,请记住这些固定的目录结构。
四、构建一个HelloMaven项目
上面介绍完了我们该使用怎样的约定来开发一个项目,接下来我们创建一个项目。
new一个maven项目,写好坐标(待会介绍)。这里说的坐标就是上面的groupid以及artifact id。创建好之后的结构如下图所示:
接下来我们尝试编译下这个项目,命令行进入项目路径,使用mvn compile命令(当然,直接在eclipse上run as这个项目使用maven的几个选项都是可以的)。编译之后会生成target目录,里面存放的是class文件 :
我们接下来编译下 :
我们查看下项目目录 :
我们这里在maven项目的测试类中写个syso输出 :
OK,我们再在控制台输入mvn clean ,清理下class文件,再输入mvn compile 再次编译一下,接着输入mvn test执行AppTest.class文件:
我们可以看到已经输出成功了。
五、 常用构建命令
从第3步骤可以看出,这些命令的使用了,其实很像使用java命令编译对不对。那么我们来介绍下maven的这些构建命令 : 其形式一般都是在命令行 mvn xxx的这种格式 :
mvn {
-v 查看maven版本以及其他相关信息
compile 编译maven项目,并生成target文件夹
test 运行test目录下的测试文件,即测试
package 将项目打包,默认打包为jar格式,也可以打包成war格式用于服务器运行
install 将打包的jar文件安装到maven本地仓库
clean 删除target,相当于清除缓存
}
这些命令在集成了maven的eclipse当中也有对应选项可以操作 :
我们可以右键一个项目,然后run as 就会出现这些选项,在下面的maven当中 还有update选项;
那这么多命令,我们怎么知道怎么合理使用呢,其实我们只需要理解到整个项目的构建过程就可以明白这一点了:
项目构建过程包括【清理项目】→【编译项目】→【测试项目】→【生成测试报告】→【打包项目】→【部署项目】这几个步骤,这六个步骤就是一个项目的完整构建过程。(mvn clean -> mvn compile -> mvn test -> mvn package)
而上面所说的maven update是针对我们在项目中的pom.xml当中引入了新的jar包之后,需要重新update一下,此处的应用场景就是 :
比如我们A项目在pom.xml引入了一个新包,这个时候我们需要把A项目重新update一下才能使用新jar包当中的东西(不过很多时候我们项目有自动重构);如果这个时候我们B项目引用了A,也想使用这个新jar包,我们也应当update一下,避免发生引用错误,还有一个常见的使用场景就是我们import一个新的maven聚合项目的时候,需要clean install :
然后我们还要update把jar包下下来,这个时候如果依赖包过多,其下载是相当大的,所以我们可以指定maven仓库的位置为阿里的(更改setting文件后面作出介绍。)
下面我列举一下常用的maven 命令(注意我上面在eclipse当中不是maven clean 而是clean,原因吗我也不知道啦):
- 创建一个简单的Java工程:mvn archetype:create -DgroupId=com.mycompany.example -DartifactId=Example
- 创 建一个java的web工程:mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mycompany.app -DartifactId=my-webapp
- 打包:mvn package
- 编译:mvn compile
- 编译测试程序:mvn test-compile
- 清空:mvn clean
- 运行测试:mvn test
- 生成站点目录: mvn site
- 生成站点目录并发布:mvn site-deploy
- 安装当前工程的输出文件到本地仓库: mvn install
- 安 装指定文件到本地仓库:mvn install:install-file -DgroupId=<groupId> -DartifactId=<artifactId> -Dversion=1.0.0 -Dpackaging=jar -Dfile=<myfile.jar>
- 查看实际pom信息: mvn help:effective-pom
- 分析项目的依赖信息:mvn dependency:analyze 或 mvn dependency:tree
- 跳过测试运行maven任务: mvn -Dmaven.test.skip=true XXX
- 生成eclipse项目文件: mvn eclipse:eclipse (将maven项目转换成eclipse项目)
- 查看帮助信息:mvn help:help 或 mvn help:help -Ddetail=true
- 查看插件的帮助信息:mvn <plug-in>:help,比如:mvn dependency:help 或 mvn ant:help 等等。
这里我还想多说一点,其实maven的功能不仅仅是这样,如下我列举一些maven的常用基本功能 :
(转载自 https://www.cnblogs.com/adolfmc/archive/2012/07/31/2616908.html)
- 构建:比如生成class、jar、war或者ear文件
- 生成文档:比如生成javadoc、网站文档
- 生成报告:比如junit测试报告
- 生成依赖类库:生成文档,说明项目多其他软件的依赖
- 有关SCM:SCM(Software Configuration Management),软件配置管理,比如版本控制,比如bug管理等等
- 发布:生成供发布的分发包,比如生成Struts2的分发包,供提交给用户使用
- 部署:比如,web应用程序,自动部署到指定的服务器上
-
Maven资源
-
见官方网站;
-
The 5 minute test,官方简易入门文档;
-
Getting Started Tutorial,官方入门文档;
-
Build Cookbook,官方的cookbook;
-
POM Reference,POM文件的设置参考
-
Settings Reference ,settings文件的设置参考
-
Better Builds with Maven,免费的电子书,下载需要注册。
-
六、坐标和仓库
坐标 :
maven使用groupId、artifactId、version表示坐标,每个坐标都唯一的指向一个maven项目,简单介绍一下这几个标签
groupId:项目组织唯一的标识符,一般为反写的公司网址+项目名
artifactId:项目的唯一的标识符,一般为项目名+模块名
version:版本号 x.x.x+版本类型
第一个x表示大版本号
第二个x表示分支版本号
第三个x表示小版本号(可省略)
常见版本类型:
snapshot快照
alpha内部测试
beta公测
release稳定
GA正式发布
注:包名应与groupId+artifactId相吻合。
仓库 : maven的依赖管理是靠着仓库来支撑的,仓库分为中央仓库和本地仓库。在编译项目时,maven会根据配置的依赖,现在本地仓库中进行搜索,若是没有则再去仓库进行搜索,而搜索便是采用坐标进行查找。仓库默认为本地的c盘users文件夹下面的.m2的repository。如果不想放在C盘的话,可以对maven进行配置:
如图,可以自己重写localRepository;
七、生命周期 & 插件的使用
多个生命周期之间相互独立。每个生命周期含有多个阶段,阶段按顺序执行,运行后阶段时,前阶段会自动执行。比如,直接运行mvn test命令,那么执行该命令时,会自动的附带mvn compile命令,因为test阶段在compile阶段之后。
上面我们就说过,一个完整的项目的构建过程包括 :
清理、编译、测试、打包、集成测试、验证、部署;
clean 清理项目,包括以下阶段:
pre-clean 执行清理前
clean 清理上一次构建生成的所有文件
post-clean 执行清理后的文件
default 构建项目(核心:常用),包括以下阶段
compile 编译
test 测试
packeage 打包
install 安装
site 生成项目站点,根据pom中信息生成项目站点,包括以下阶段
pre-site 在生成项目站点前要完成的工作
site生成项目的站点文档
post-site在生成项目站点后要完成的工作
site-deploy发布生成的站点到服务器上
插件:
maven中提供了许多功能强大的插件,让我们更好的管理项目。一个插件通常提供了一组目标,可使用以下语法来执行:
mvn [plugin-name]:[goal-name]
例如我们之前使用mvn archetype:generate,插件名为archetype,而目标为generate。我们可以在官网的Plugins标签下,查找到插件的坐标及插件目标的详细描述。
Maven 提供以下两种类型插件:
类型 | 描述 |
---|---|
构建插件 | 在生成过程中执行,并在 pom.xml 中的<build/> 元素进行配置 |
报告插件 | 在网站生成期间执行,在 pom.xml 中的 <reporting/> 元素进行配置 |
以下是一些常见的插件列表:
插件 | 描述 |
---|---|
clean | 编译后的清理目标,删除目标目录 |
compiler | 编译 Java 源文件 |
surefile | 运行JUnit单元测试,创建测试报告 |
jar | 从当前项目构建 JAR 文件 |
war | 从当前项目构建 WAR 文件 |
javadoc | 产生用于该项目的 Javadoc |
antrun | 从构建所述的任何阶段运行一组 Ant 任务 |
source | 从当前项目构建带源码的JAR文件 |
比如我们拿source来测试:
1 <build> 2 <!-- 配置插件集 --> 3 <plugins> 4 <plugin> 5 <!--使用插件的坐标进行引用 --> 6 <groupId>org.apache.maven.plugins</groupId> 7 <artifactId>maven-source-plugin</artifactId> 8 <version>3.0.0</version> 9 10 <executions> 11 <execution> 12 <!-- 绑定在哪个过程时一同执行,这里我们让它在使用package打包时一同执行 --> 13 <phase>package</phase> 14 <!--执行的目标类型,关于目标的详细介绍可以在maven官网中查到--> 15 <goals> 16 <goal>jar-no-fork</goal> 17 </goals> 18 </execution> 19 </executions> 20 </plugin> 21 </plugins> 22 </build>
我们接下来先编译一下 :
然后,我们在来看使用打包命令之后会不会生成源jar包。
我们可以看到在下载很多东西了 ,接下来看下文件夹生成了源jar包没 :
从这里我们可看成,这里有几个关键点,在pom.xml当中使用plugin来申明要使用的插件,然后还可以绑定到某个过程中执行,我们这里就绑定到了package当中执行。
八、 pom.xml常用标签介绍
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <!-- 当前pom的版本--> 4 <modelVersion>4.0.0</modelVersion> 5 6 <!--坐标--> 7 <groupId>cn.edu</groupId> 8 <artifactId>maven04</artifactId> 9 <version>0.0.1-SNAPSHOT</version> 10 <!-- 默认是jar,其他war zip pom等 --> 11 <packaging>jar</packaging> 12 13 <!--项目描述名 --> 14 <name>maven04</name> 15 <!-- 项目地址 --> 16 <url>http://maven.apache.org</url> 17 18 <!-- 配置参数 --> 19 <properties> 20 <!-- 这里配置项目编译编码为UTF-8--> 21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 22 </properties> 23 24 <!-- 开发人员信息 --> 25 <developers></developers> 26 <!-- 项目描述 --> 27 <description></description> 28 <!-- 许可信息 --> 29 <licenses></licenses> 30 <!-- 组织信息 --> 31 <organization></organization> 32 <!-- 依赖集,用于配置依赖 --> 33 <dependencies> 34 <dependency> 35 <groupId>junit</groupId> 36 <artifactId>junit</artifactId> 37 <version>3.8.1</version> 38 39 <!-- 依赖范围:这个jar包只在范围内生效,范围外引用会报错,这里让junit只在test时被依赖。 40 其他一些情况,如:servlet-api.jar,在编译阶段需要引用,而在服务器运行阶段则不需要引用,就可以使用scope--> 41 <scope>test</scope> 42 43 <!-- 默认为false,子项目将会继承,true时子项目并需显式引用 --> 44 <optional>false</optional> 45 46 <!-- 排除依赖列表:用于去除传递依赖等,在后面会详细介绍--> 47 <exclusions> 48 <exclusion></exclusion> 49 </exclusions> 50 51 </dependency> 52 </dependencies> 53 54 <!-- 依赖管理 55 为依赖进行统一管理,如果在父项目中声明此标签时,在子项目中不需声明,确保父子项目依赖版本一致; 56 如子项目需要不同版本的依赖,只需在子项目中进行声明即可,将会覆盖父项目中的声明。 57 --> 58 <!-- 59 <dependencyManagement> 60 <dependencies> 61 <dependency></dependency> 62 </dependencies> 63 </dependencyManagement> 64 --> 65 66 <!--配置构建时的属性--> 67 <build> 68 <plugins></plugins> 69 </build> 70 71 <!-- 指定父模块 --> 72 <!-- <parent></parent> --> 73 74 <!-- 用于聚合编译多个maven模块 --> 75 <modules></modules> 76 </project>
九、 maven依赖 (范围、传递、冲突)
范围:
首先要知道,maven中提供了三种classpath:编译、测试、运行
scope标签
-compile 默认,编译测试运行均有效,会传递
-provided 在编译和测试时有效,如servletAPI可以加入,不传递
-runtime 在测试和运行时有效,如JDBCAPI可以加入
-test 在测试时有效,如junit可以加入
-system 在编译和测试时有效,与本机系统相关联,移植性差,在系统中以外部jar包的形式引入,不会在仓库中查找
-import 导入,只能用在dependecyManagement中,表示从其他pom中导入dependecy的配置
传递:
先来看看什么是传递依赖,比如现在有这么个情况:
C依赖B、B依赖A——C→B→A,那么此时C也会依赖A且会包含A中的依赖,这就是传递依赖。接下来我们通过一个例子来详细了解依赖及如何消除传递依赖:
现有ABC三个项目:
A中额外依赖了一个commons-io的jar包:
B中对A进行依赖:
C中对B进行依赖:
保存之后可以看到,C中不但包含B,还包含A和A依赖的common-io:
那么如何消除传递依赖呢,这里就使用到<exclusion>标签了,在C中配置依赖B的地方加入以下内容:
保存后就可以看到,C中关于A的依赖消失了,传递依赖的问题就解决了。
冲突:
假设现在有这么个情况:A依赖common-io的2.4版本,B依赖common-io的2.5版本,C依赖A、B,那么此时C中的common-io是哪个版本的?
这就是依赖冲突,在maven中应对依赖冲突有两种解决方式:短路优先,先声明优先
先声明优先:顾名思义,在pom中,写在配置文件上面的优先,比如此时A的依赖配置在B之上,那C中就为2.4版本的common-io。
短路优先:优先选择依赖路径较短的一端。假设现在多出一个D,依赖情况改为D依赖B,C依赖A、D——C→A、C→D→B,那么这里就是A的依赖路径比较短,所以为2.4版本。
十、聚合&继承
聚合:
试想一下这样的情况,在一个项目中,分模块使用了maven,那么可能在这个项目中会有五六个,或者更多的maven项目存在。如果此时需要编译或测试要怎么办呢,进入每个maven项目中进行mvn compile么,那就要执行五六次的compile命令,十分繁琐,这里就可以用maven的聚合来解决这个问题。
现有ABC三个工程,那么我们使用一个新的工程D,来聚合他们,以后只要对D进行编译即可对三个工程同时进行编译。使用module标签进行聚合:
1 <modules> 2 <!--这里的路径是基于D项目的pom.xml路径,module标签内为指向其他项目的pom文件的路径 3 这里我的ABCD项目在同一个文件夹内,那么从D内的pom中,通过../项目名,来找到其他项目的pom.xml--> 4 <module>../A</module> 5 <module>../B</module> 6 <module>../C</module> 7 </modules>
继承:
另一种情形,如果多个maven项目具有相同的依赖时或配置时,那么应该如何处理呢?这里就用到继承的概念,在maven中使用<parent>标签来进行继承,下面通过一个例子来看一下:
首先建立一个项目,命名为parent,在parent的pom文件声明一个common-io的依赖,不过这里用到了dependencyManagement:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 5 <groupId>cn.edu</groupId> 6 <artifactId>parent</artifactId> 7 <version>0.0.1-SNAPSHOT</version> 8 <packaging>pom</packaging> 9 10 <name>parent</name> 11 <url>http://maven.apache.org</url> 12 13 <properties> 14 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 15 </properties> 16 17 <dependencies> 18 <dependency> 19 <groupId>junit</groupId> 20 <artifactId>junit</artifactId> 21 <version>4.12</version> 22 <scope>test</scope> 23 </dependency> 24 </dependencies> 25 26 <dependencyManagement> 27 <!-- 在这里声明的依赖可以被子项目继承引用 --> 28 <dependencies> 29 <dependency> 30 <groupId>commons-io</groupId> 31 <artifactId>commons-io</artifactId> 32 <version>2.4</version> 33 </dependency> 34 </dependencies> 35 </dependencyManagement> 36 </project>
可以看到,虽然我们在父项目中配置了依赖,但是却不会在父项目中被引用:
在子项目B中,配置继承parent并使用parent中的common-io版本:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 5 6 <groupId>cn.edu</groupId> 7 <artifactId>B</artifactId> 8 <version>0.0.1-SNAPSHOT</version> 9 <packaging>jar</packaging> 10 11 <name>B</name> 12 <url>http://maven.apache.org</url> 13 14 <properties> 15 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 16 </properties> 17 18 <!-- 在parent标签中使用父项目的坐标进行配置 --> 19 <parent> 20 <groupId>cn.edu</groupId> 21 <artifactId>parent</artifactId> 22 <version>0.0.1-SNAPSHOT</version> 23 </parent> 24 25 <dependencies> 26 <!-- 此处使用依赖时,就不需声明版本 --> 27 <dependency> 28 <groupId>commons-io</groupId> 29 <artifactId>commons-io</artifactId> 30 </dependency> 31 32 <dependency> 33 <groupId>junit</groupId> 34 <artifactId>junit</artifactId> 35 <version>4.12</version> 36 <scope>test</scope> 37 </dependency> 38 </dependencies> 39 </project>
配置后保存即可看到,此处的依赖版本即为父项目中的版本: