Maven基础
Web项目开发理论
视图层:直接负责Web页面的表现
控制层:控制页面表现
持久化层:与数据库和存储交互
目前开发所存在的问题
-
一个项目就是一个工程
如果一个项目非常庞大,就不再适合使用package划分模块,最好每一个模块对应一个工程,利于分工协作。
而借助于maven,就可以将一个项目拆分为多个
-
项目中需要的jar包必须手动复制粘贴到WEB-INF/lib目录下
带来的问题是,同样的jar包文件重复出现在不同的工程中。一方面浪费存储,另一方面也使得工程更加臃肿
借助maven,可以将jar包仅仅保存在仓库中,有需要的话引用即可,不需要真的复制
-
jar包需要别人替我们准备好或到各自的官网下载
下载很麻烦,或者有些官网就是通过maven或者SVN提供下载的,不直接提供jar包
借助于maven,我们可以使用一种统一的、正式的方式下载资源,也保证了内容的可靠性
-
一个jar包依赖的其他jar包需要自己手动加入项目
maven会自动将依赖的所有jar包导入
概念
-
Maven是一款服务于java平台的自动化构建工具
-
Make->Ant->Maven->Gradle(确实比maven好用,之后可以自学试一试)
-
构建:以java源文件、框架配置文件、JSP、html、图片等资源为原材料,去生成一个运行的项目的过程
-
tips,对于运行时环境,例如JRE,我们的项目中并不会包括,只是对jar包的引用,需要客户端手动下载才可以(运行时环境也不一定只有JRE,我们也可以设置依赖为运行时环境)
-
此外,项目结构和web项目部署的目录也有差别,这是项目编译的结果:
左图是项目的目录结构,有图是部署后的目录结构。可以看到部署后的WEB-INF下就是项目的build下的内容,而src目录下的内容则不会加入部署的项目结构中(因为运行不需要源码),此外,webContent中除了WEB-INF之外的内容会直接放在部署的项目的根目录下所以说,开发过程中,所有的路径或者配置文件中配置的类路径都应该是以编译结果的目录结构为标准的
-
构建过程的几个主要环节:
- 清理:将以前编译得到的旧的class文件删除
- 编译
- 测试:自动化测试,好处是对于重要的环节可以通过提前编写测试junit文件的方式来保证每次构建时都对这些环节进行测试,以保证他们的正确性
- 报告:测试程序输出的结果
- 打包:动态Web工程打war包,java打jar包
- 安装:将打包得到的文件复制到仓库的指定位置(是maven独有的概念)
- 部署:将动态web工程生成的war包复制到servlet容器的指定目录下,使其可以运行
自动化构建可以将这些机械化的内容自动完成
-
-
约定的目录结构
根目录:工程名
src:源码
pom.xml:maven工程的核心配置文件
main目录:存放主程序
test目录:存放测试程序
java目录:存放java源文件
resources目录:存放框架或者其他工具的配置文件
-
为什么要遵守约定的目录结构
-
Maven以该目录结构为基础进行项目的自动化构建
-
IDEA有在添加maven框架后自动按要求配置目录结构的功能.
-
如果有我们自定义的东西,我们有两种方法让框架或者工具知道,一种是以配置的方式明确告知框架(例如在pom.xml中进行配置),另一种是遵守框架内部已经存在的约定
行业共识:约定>配置>编码,能用前面的解决就不要用后面的
-
-
-
使用maven,我们不仅可以方便的添加从互联网下载的jar包的依赖,也可以方便地添加本地依赖(前提是本地依赖也存放的本地仓库中)
运行
- 将maven核心程序下载并解压
- 配置maven环境变量
(如果是用IDEA就用内置的maven就好了,没有配置环境变量等等麻烦了就)
- 运行mvn -v查看是否正常运行
常用maven命令
注意,执行与构建过程相关的maven命令(编译、测试、打包等等),必须进入pom.xml所在的目录
maven的核心程序仅仅定义了抽象的生命周期,具体的工作必须由特定的插件来完成,所以第一次使用会去下载这些插件,之后会去本地仓库调用。本地仓库的位置是:~/.m2/repository
修改maven本地仓库的位置
本地仓库的默认位置是:~/.m2/repository
- 找到maven的解压目录\\conf\\settings.xml
- 找到localRepository标签,修改路径并取消注释
pom.xml
project object model:项目对象模型,类似的还有DOM(document object model,文档对象模型)
坐标
maven中的坐标:使用三个向量,在仓库中唯一定位一个maven工程
groupid:公司或组织域名倒序+项目名
artifactid:模块名
version:版本
由这三个属性的开头字母,有时候人们也把maven坐标称为gav
maven工程的路径和坐标的对应关系
看图便知:
仓库
仓库分为本地仓库和远程仓库,远程仓库分为局域网的仓库(也称为私服)、中央仓库和中央仓库的镜像
-
私服:搭建在局域网中,为局域网的所有maven工程服务.Nexus就是maven私服的产品。用户访问私服,如果私服中没有该Jar包,就由私服从中央仓库进行下载。
私服的作用,就是因为在软件开发中,有可能不能所有的电脑都可以上外网
-
中央仓库:架设在internet上,为全球服务
-
中央仓库的镜像:分担中央仓库的流量、加快访问速度
仓库中保存的内容
仓库中保存的是maven工程,但是这些工程可以分为:
- maven自身所需要的插件
- 第三方框架或者工具的jar包
- 我们自己开发的maven工程
工程版本分类
- release:当前版本开发完成
- snapshot:未开发完成的版本
依赖
依赖的范围
注意看pom.xml里,不同的依赖有自己的适用范围:
不同范围的依赖区别在于:
-
对主程序是否有效
-
对测试程序是否有效
-
是否参与打包
-
compiler
- 对主程序和测试程序都有效
- 参与打包
- 典型例子:spring-core
-
test
- 对测试程序有效
- 不参与打包
- 典型例子:junit
-
provided
- provided的依赖比较特别,是专门用于开发时候解决没有部署时的环境的问题的,也就是它提供了运行的环境,但是由于部署时本身机器就有这个环境、只是开发的时候没有,所以这个包:
- 对主程序和测试程序都有效
- 不参与打包
- 典型例子:servlet-api.jar
- 注意,如果将应该设置为provided的依赖设置为了compiler,就会在部署的时候和服务器环境发生冲突
依赖的传递性
直接依赖:写入pom.xml的依赖
传递依赖:直接依赖的模块所依赖的模块,不写入pom.xml,但是实际上依然会加入。
直接依赖的模块修改了它的依赖,也就是传递依赖,也会对我们的模块产生影响
好处:可以传递的依赖不需要在每个模块工程中都重复说明。我们可以设置一个模块,专门用于维护项目的依赖信息
注意,非compiler范围的依赖不能传递。如果需要使用的话就需要重复声明
如果同一个模块分别被直接依赖和间接依赖,但是版本不同,则首先使用直接依赖的版本
依赖的排除
但是这种传递的依赖有时候我们是不想要的(eg.传递依赖是不稳定版本),这种情况下,我们可以对依赖进行排除
配置exclusion标签即可
依赖的原则
-
作用:解决模块工程之间的jar包冲突问题
-
处理依赖冲突的原则:就近原则
例如上图,HelloFriend和Hello都依赖log4j,但是版本不一样,而MakeFriend直接依赖与HelloFriend,间接依赖于Hello,所以它首先采用HelloFriend所依赖的log4j版本 -
距离一样时,先声明者优先
也就是这种情况:
如果HelloFriend先声明,则使用1.2.14版本的,否则使用1.2.17版本的
统一管理依赖版本
我们往往需要统一依赖的模块中某一模块的版本为特定版本,这时候通过手动在pom.xml设置版本对于中大型工程显然是不靠谱的
建议配置方式:
- 使用properties标签使用自定义标签统一声明版本号
- 在需要统一版本的地方使用${自定义标签名}
例如:
先配置:
在使用的时候:
在properties标签内自定义标签并使用,这种方式不限于统一管理依赖版本,可以使用在所有需要统一声明后再应用的场景
生命周期
关于maven构建的生命周期,可以看我的这篇博文
涉及到生命周期的命令
- mvn clean:清理,删除target文件夹
- mvn compile:编译,生成target\\classes目录,其中放的是编译后的java class文件
- mvn test-compile:编译测试程序,生成target\\test-classes目录
- mvn test:测试
- mvn package:打包,生成辅助性文件夹maven-archiver,测试报告文件夹surefire-reports以及jar包
- mvn install:将项目安装进本地仓库
- mvn site:生成站点
Default生命周期
了解生命周期有一个简单的办法:不论现在要执行生命周期中的哪一个阶段,都是从这个生命周期最初的位置开始执行:
导入maven工程
例如在eclipse中,如果是我们手动创建的工程,eclipse是无法直接导入的,因为它缺少了eclipse需要的工程配置文件。但如果它有maven框架的话,就可以作为一个maven工程导入,因为maven工程只扫描是否有pom.xml
继承
操作步骤
-
创建一个maven工程作为父工程,注意打包的方式是pom
-
在子工程中声明对父工程的引用
在所有使用junit的地方都声明对父工程的引用
-
将子工程的坐标与父工程坐标中重复的内容删除
-
在父工程中统一管理junit的依赖
-
在子工程中删除junit依赖的版本号学习
当然,如果要使用和父工程不一样的版本,可以保留,会优先使用子工程中的设置
注意,配置了继承之后,执行mvn install命令时要先对父工程进行install
聚合
一键安装(install)父工程、子工程等各个模块工程
配置方式:在一个总的聚合工程(父工程)中配置各个参与聚合的模块
对于各个模块之间的依赖关系maven可以自动识别,所以说模块的顺序可以随意
Web工程的自动部署
一般地,我们可以使用maven对web工程进行打包,然后放在服务器上。但是maven确实也支持web缓存的自动部署(其实IDE也都支持这种功能,但是都是部署在本机,不是远程的服务器)
配置方法:配置build
build标签是用于配置当前工程构建过程中的特殊设置
我在这篇博客中也提到了build标签和plugins插件的使用
但是好像还是不如IDE的好用,例如在eclipse中会有无法terminate的问题