传统工程存在的问题
1、一个项目就是一个工程
如果项目非常庞大,就不适合继续使用package来划分模块。最好是每一个模块对应一个项目,利于分工协作。
借助于maven就可以将一个项目拆分成多个工程。
2、项目中需要的jar包必须手动“复制”、”粘贴” 到WEB-INF/lib 项目下
带来的问题:同样的jar包文件重复出现在不同的项目工程中,一方面浪费存储空间,另外也让工程比较臃肿。
借助Maven,可以将jar包仅仅保存在“仓库”中,有需要使用的工程“引用”这个文件,并不需要重复复制。
3、jar包需要别人替我们准备好,或到官网下载
所有知名框架或第三方工具jar包已经按照统一规范放在了Maven的中央仓库中。
4、一个jar包依赖的其他jar包需要自己手动加到项目中
Maven会自动将被依赖的jar包导入进来。
Maven是什么
Maven是一款服务于Java平台的自动化构建工具
构建过程中的各个环节
1、清理:将以前编译得到的class字节码文件删除,为下一次编译做准备
2、编译:将Java源程序编译成class字节码文件
3、测试:自动测试,自动调用junit程序
4、报告:测试程序执行的结果
5、打包:Java工程打jar包,web工程打war包
6、安装:将打包得到的文件复制到“仓库”中的指定位置
7、部署:将动态web工程生成的war包复制到servlet容器的指定目录下
Maven的核心概念
1、约定的目录结构
我们在开发中如果需要让第三方工具或框架知道我们自己创建的资源在哪,那么基本上就是两种方式:
①以配置文件的方式明确告诉框架
②遵循框架内部已经存在的约定(maven使用约定的目录结构)
2、POM
3、坐标
4、依赖
5、仓库
6、生命周期/插件/目标
7、继承
8、聚合
常用的maven命令
执行与构建过程相关的maven命令,必须进入pom.xml所在的目录
与构建过程相关:编译、测试、打包…
mvn clean:清理
mvn compile:编译主程序
mvn test-compile:编译测试程序
mvn test:执行测试
mvn package:打包
mvn install:安装
mvn site:生成站点
关于联网的问题
maven的核心程序中仅仅定义了抽象的生命周期,但是具体的工作必须由特定的插件来完成。
maven核心程序如果在本地仓库中找不到需要的插件,那么它会自动链接外网到中央仓库下载
POM project object model
maven工程核心配置文件,与构建过程相关的一切设置都再这个文件中进行配置
Maven的坐标
使用下面三个属性在仓库中唯一定位maven工程
1、groupid:公司或组织域名+项目名称
2、artifactid:模块名称
3、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
仓库
仓库的分类
本地仓库:当前电脑上部署的仓库目录,为当前电脑上所有Maven工程服务
远程仓库:
私服:搭建在局域网环境中,为局域网范围内的所有Maven工程服务
中央仓库:架设在internet上,为全世界所有Maven工程服务
中央仓库映像:为了分担中央仓库的流量,提升用户访问速度
仓库中保存的内容:Maven工程
maven自身所需要的插件
第三方框架或工具的jar包
我们自己开发的maven工程
依赖
maven解析依赖信息时会到本地仓库中查找被依赖的jar包
对于我们自己开发的maven工程,使用install命令就可以把jar包安装到本地仓库中
依赖的范围
compile:
对主程序是否有效:有效
对测试程序是否有效:对测试程序有效
是否参与打包:参与打包
test、
对主程序是否有效:无效
对测试程序是否有效:对测试程序有效
是否参与打包:不参与打包
provided
对主程序是否有效:有效
对测试程序是否有效:对测试程序有效
是否参与打包:不参与打包
是否参与部署:不参与
compile与test范围的对比
在maven工程中有测试代码部分和核心代码部分
对于核心代码部分,它可以看到声明为compile范围的依赖jar包
对于测试代码部分,它可以看到声明为compile和test范围的依赖jar包
例如tomcat,它在运行时会提供servlet-api.jar包,如果我们再将该jar包导入项目中,那么在运行时会出现jar包冲突。我们只是需要在开发阶段用到该jar包,等到项目部署、运行时使用tomcat的就可以了。因此可以使用provided声明该依赖jar包的范围
生命周期
maven的核心程序中定义了抽象的生命周期,生命周期中各个阶段的具体任务是由插件来完成的
maven有三套相互独立的生命周期,分别是:
1、Clean Lifecycle 在构建之前进行一些清理工作
2、Default Liftcycle 构建的核心部分,编译、测试、打包、安装、部署
3、Site Liftcycle 生成项目报告,站点,发布站点
maven核心程序为了更好的实现自动化构建,按照这一特点执行生命周期中各个阶段:不论现在要执行生命周期中的哪一个阶段,都是从这个生命周期最初的位置开始执行
依赖的传递性
当前项目依赖于HelloFriend,而HelloFriend又依赖于Hello,Hello又依赖于spring-core …
maven会将该依赖层次(直接依赖与间接依赖)都导进来
注意:非compile依赖范围的不能进行传递,例如如果Hello依赖于junit,那么这个依赖不能传递到HelloFriend
依赖的排除
需要设置依赖排除的场景
使用exclusions设置排除依赖
依赖的原则
1、路径最短者优先原则
Hello 依赖于log4j.1.2.17 HelloFriend 依赖于log4j.1.2.14,那么在MakeFriends中会存在两个间接依赖的jar包
maven根据就近原则会去选择log4j.1.2.14的jar
2、路径相同时先声明者优先
例如在MakeFriends的POM文件中先声明HelloFriend的dependency,那么就使用它依赖的log4j.1.2.14jar
统一管理依赖的版本
1、在properties标签内自定义便签统一声明版本号
<properties>
<jason.junit.version>4.11</jason.junit.version></properties>
2、在需要统一版本的依赖中,使用${自定义标签名}引用声明的版本号
<version>${jason.junit.version}</version>
凡是需要统一声明后再引用的场合都可以使用properties配合自定义标签
继承
现状
Hello依赖的junit:4.0
HelloFriend:依赖junit:4.9
要求:统一管理各个模块工程对junit依赖的版本(因为junit的范围是test,test是不会传递的)
由于test范围的依赖不能传递,必然会分散在各个模块工程中,很容易造成版本不一致
解决的思路:将junit依赖统一提取到“父”工程中,在子工程中声明junit依赖时不指定版本,以父工程中统一设定的为准,同时也便于修改
操作步骤:
1、创建一个Maven工程作为父工程,打包的方式为POM
2、在子工程中声明对父工程的引用
3、将子工程的坐标中与父工程坐标 中重复的内容删除
4、在父工程中统一junit依赖
5、在子工程中删除junit依赖的版本号
Maven parent.relativePath
默认值为…/pom.xml
查找顺序:relativePath元素中的地址–本地仓库–远程仓库
设定一个空值将始终从仓库中获取,不从本地路径获取。
聚合
作用:一键安装各个模块工程
配置方式:在一个“总的聚合工程”中配置各个参与聚合的模块
<!-- 配置聚合 -->
<modules>
<!-- 指定各个模块的相对路径 -->
<module>Child01</module>
<module>Child02</module>
</modules>
再聚合工程中调用install