简介
背景[why]
我们为什么要学这个Maven呢?按照目前我们学习过的技术,已经是可以做一个项目的了,现在我们已经有的知识:
利用前面的技术,我们已经可以做一个完整的项目了,但是存在很多的问题,
目前的技术在开发中存在的问题
-
一个项目就是一个工程
如果项目非常庞大,就不适合继续使用package来划分模块。最好是每一个模块对应一个工程,利于分工协作。
借助于Maven就可以将一个项目拆分成多个工程。 -
项目中需要的jar包必须手动“复制”、“粘贴”到WEB-INF/ib目录下
带来的问题是:同样的jar包文件重复出现在不同的项目工程中,一方面浪费存储空间,另外也让工程比较臃肿。
借助Maven,可以将jar包仅仅保存在“仓库”中,有需要使用的工程“引用”这个文件接口,并不需要真的把jar包复制过来。 -
jar包需要别人替我们准备好,或到官网下载
不同技术的官网提供jar包下载的形式是五花八门的。
有些技术的官网就是通过Maven或SVN等专门的工具来提供下载的。
如果是以不规范的方式下载的jar包,那么其中的内容很可能也是不规范的。
借助于Maven可以以一种规范的方式下载jar包。因为所有知名框架或第三方工具jar包以及按照统一的规范存放在了Maven的中央仓库中。
以规范的方式下载的jar包,内容也是可靠的。 -
一个jar包依赖的其他jar包需要自己手动加入到项目中
FileUpload组件一I0组件。commons-fileupload-1.3.jar依赖于commons-io-2.0.1.jar。
如果所有jar包之间的依赖关系都需要程序员自己非常清楚的了解,那么就会极大的增加学习成本。
Maven会自动将被依赖的jar包导入进来。
Maven是什么[What]
Maven是一款服务于Java平台的自动化构建工具。
经历的过程:Make→Ant→Maven→Gradle
了解完Maven可以再去了解Gradle
构建
概念:以“Java源文件”、“框架配置文件”、“JSP”、"HTML”、“图片”等资源为“原材料”,去“生产”一个可以运行的项目的过程。
构建并不是创建,创建一个工程并不等于构建一个项目。要了解构建的含义我们应该由浅入深的从 以下三个层面来看:
①纯 Java 代码 大家都知道,我们 Java 是一门编译型语言,.java 扩展名的源文件需要编译成.class 扩展名的字节码 文件才能够执行。所以编写任何 Java 代码想要执行的话就必须经过编译得到对应的.class 文件。
②Web 工程 当我们需要通过浏览器访问 Java 程序时就必须将包含 Java 程序的 Web 工程编译的结果“拿”到服务 器上的指定目录下,并启动服务器才行。这个“拿”的过程我们叫部署。
③实际项目 在实际项目中整合第三方框架,Web 工程中除了 Java 程序和 JSP 页面、图片等静态资源之外,还 包括第三方框架的 jar 包以及各种各样的配置文件。所有这些资源都必须按照正确的目录结构部署到服 务器上,项目才可以运行。
三方面对应这三个过程:编译–>部署–>搭建
编译:Java源文件[Userjava]一编译一Class字节码文件[User.clas]一交给VM去执行
部署:一个BS项目最终运行的并不是动态Web工程本身,而是这个动态Web工程“编译的结果"
可以发现,编译之后,WebContent这个目录不存在了,项目的名称作为最大的目录,WebContent下面的内容编译后放在工程目录下,src编译的结果放在WEB-INF类路径下
开发过程中,所有的路径或配置文件中配置的类路径等都是以编译结果的目录结构为标准的。
运行环境的认识
这些都是运行环境,代码是没有直接在项目的文件里面的
构建过程的环节
清理:将以前编译得到的旧的class字节码文件删除,为下一次编译做准备
编译:将Java源程序编程成class字节码文件测试:自动测试,自动调用junit程序
报告:测试程序执行的结果
打包:动态Web工程打war包,Java工程打jar包
安装:Maven特定的概念——将打包得到的文件复制到“仓库”中的指定位置
部署:将动态Web工程生成的war包复制到Servlet容器的指定目录下,使其可以运行
安装Maven
- 因为Maven本来就是java写的,所以也需要jvm的运行环境,检查电脑是否有JAVA_HOME环境变量
- 解压你的Maven的压缩包
- 配置Maven的相关环境变量
MAVEN_HOME的变量名,对应解压的Maven压缩包的bin的上一级目录
path路径,对应解压的Maven压缩包的bin的下一级目录 - 允许mvn -v来查看maven的版本,能看到就说明成功了
Maven的核心概念
常用的Maven命令
注意:执行与构建过程相关的Maven命令,必须进入pom.xml所在的目录。
与构建过程相关:编译、测试、打包、……
常用命令
[1]mvn clean:清理
[2]mvn compile:编译主程序
[B]mvn test-compile:编译测试程序
[4]mvn test:执行测试
[5]mvn package:打包
[6]mvn install:安装
[7]mvn site:生成站点信息,就是html信息
初次执行上面的命令需要联网的,因为Maven需要某些插件,而你电脑没有,他会去中央仓库下载回给你
①Maven的核心程序中仅仅定义了抽象的生命周期,但是具体的工作必须由特定的插件来完成。而插件本身并不包含在Maven的核心程序中。
②当我们执行的Maven命令需要用到某些插件时,Maven核心程序会首先到本地仓库中查找。
③本地仓库的默认位置:[系统中当前用户的家目录.m2\repository
④Maven核心程序如果在本地仓库中找不到需要的插件,那么它会自动连接外网,到中央仓库下载。
⑤如果此时无法连接外网,则构建失败。
⑥修改默认本地仓库的位置可以让Maven核心程序到我们事先准备好的目录下查找插件
[1]找到Maven解压目录\confAsettings.xml
[2]在settings.xml文件中找到localRepository标签
[3]将< localRepository>/path/to/local/repo< /localRepository>从注释中取出
[4]将标签体内容修改为已经准备好的Maven仓库目录
约定的目录结构
创建约定的目录结构
[1]根目录:工程名
[2]src目录:源码
[B]pom.xm文件:Maven工程的核心配置文件
[4]main目录:存放主程序
[5]test目录:存放测试程序
[6]ljava目录:存放Java源文件
[7]resources目录:存放框架或其他工具的配置文件
为什么要遵守约定的目录结构呢?
Maven要负责我们这个项目的自动化构建,以编译为例,Maven要想自动进行编译,那么它必须知道Java源文件保存在哪里。
如果我们自己自定义的东西想要让框架或工具知道,有两种办法:
以配置的方式明确告诉框架
遵守框架内部已经存在的约定
以后的趋势就是约定>配置>编码
POM
①含义:Project Object Model项目对象模型
和DOM Document Object Model 文档对象模型的思路差不多
②pom.xm对于Maven工程是核心配置文件,与构建过程相关的一切设置都在这个文件中进行配置。
重要程度相当于web.xml对于动态Web工程
坐标
可以类比数学中的坐标
数学中的坐标:
在平面上使用X和Y两个向量可以唯一的定位平面中的任何的一个点,空间中可以使用X,Y,Z三个向量来唯一的定位空间中的任何一点
Maven的坐标:
使用三个向量在仓库中唯一定位一个Maven工程
groupid:公司或组织域名倒序+项目名
artifactid模块名
version版本
Maven工程的坐标与仓库中的路径是对应关系的,例如:
<groupld>org.springframework</groupld>
<artifactld>spring-core </artifactld>
<version>4.0.0.RELEASE</version>
对应文件路径:
org/springframework/spring-core/4.0.0.RELEASE/spring-core-4.0.0.RELEASE.jar
路径是groupld+artifactld+version
文件名称:模块名-版本号.jar
依赖
就是本工程的类需要借助其他工程的类来实现功能
Maven解析依赖信息时会到本地仓库中查找被依赖的jar包。
对于我们自己开发的Maven工程,在工程目录使用mvn install命令安装后就可以放入仓库。
依赖的范围
依赖有compile,test和provided
- compile范围依赖
对主程序是否有效:有效
对测试程序是否有效:有效
是否参与打包:参与 - test范围依赖
对主程序是否有效:无效
对测试程序是否有效:有效
是否参与打包:不参与
典型的例子:junit - provided范围依赖
对主程序是否有效:有效
对测试程序是否有效:有效
是否参与打包:不参与
是否参与部署:不参与
典型例子:servlet-api.jar,就比如web工程开发的时候需要servlet等的jar包,所以就需要依赖servlet-api的jar包,但是在部署和运行的时候,servlet的api由tomcat服务器的servlet容器提供,不需要依赖其他东西
依赖的传递性
A 依赖 B,B 依赖 C,A 能否使用 C 呢?那要看 B 依赖 C 的范围是不是 compile,如果是则可用,否则不可用。
依赖的排除
如果我们在当前工程中引入了一个依赖是A,而 A又依赖了B,那么 Maven 会自动将A依赖的B引入当 前工程,但是个别情况下B有可能是一个不稳定版,或对当前工程有不良影响。这时我们可以在引入 A 的时 候将 B 排除。
例如:
在Hello或者HelloFriend里面写这个排除信息,在Hello里面写会影响HelloFriend也没有.
<dependency>
<groupId>maven</groupId>
<artifactId>HelloFriend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
<exclusions >
<exclusion >
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
依赖的原则
[1]作用:解决模块工程之间的jar包冲突问题
[2]情景设定1:验证路径最短者优先原则
[3]情景设定2:验证路径相同时先声明者优先
先声明指的是dependency标签的声明顺序
统一管理依赖版本
比如需要引用一系列的spring的框架,spring框架的版本号一般是需要保持一致的,如果突然需要将spring的版本号全部升级,那怎么办呢?
这么多的依赖信息,我们不可能一个一个地去改
所以建议配置方式:
- 使用properties标签内使用自定义标签统一声明数据,就是版本号
- 在需要统一版本的位置,使用${自定义标签名}引用声明的版本号
例如:
声明版本号:
<properties>
<jane>4.1.1.RELEASE</jane>
</properties>
引用:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${jane}</version>
</dependency>
properties标签配合自定义标签声明数据的配置并不是只能用于声明依赖的版本号,需要统一的数据都可以使用它来声明
仓库
仓库的分类
- 本地仓库:
当前电脑上部署的仓库目录,为当前电脑上所有Maven工程服务 - 远程仓库
(1)私服:搭建在局域网环境中,为局域网范围内的所有Maven工程服务
(2)中央仓库:架设在Internet上,为全世界所有Maven工程服务
(3)中央仓库镜像:为了分担中央仓库的流量,提升用户访问速度
仓库中保存的内容:Maven工程
[1]Maven自身所需要的插件
[2]第三方框架或工具的jar包
[B]我们自己开发的Maven工程