古语有云: 万恶淫为首,百善孝为先。 我们后辈当自勉。
上一章简单介绍了Maven的基本概念(三),如果没有看过,请观看上一章
一. Maven的生命周期
我们在第二章时,输入的那些命令,如 clean(清理),compile (编译),
test(测试),package(打包),install(安装) ,可以被 Maven 处理并且运行, 这些命令是什么? 其实这些命令都是 Maven的生命周期。 生命周期, Servlet 有生命周期, 多线程也有生命周期, Maven自然也有生命周期。
Maven 有三个标准的生命周期
clean 周期, default 周期, site(站点) 周期。
1 . clean : 项目清理的处理
2 . default 默认周期,对项目部署的处理,最主要的。
3 . site 项目站点文档创建的处理
这三个生命周期,是完全不同的生命周期,针对的不是一件事。 clean 是管 项目的清理的, default 是管项目的部署的, site 是管站点文档创建的。
一.一 clean 生命周期
clean 清理生命周期,包括三个阶段:
1 . pre-clean : 执行一些需要在 clean (第二阶段)之前执行的操作
2 . clean : 移除所有上一次构建所生成的文件。 一般指 target 目录
3 .post-clean: 执行一些需要在 clean(第二阶段) 之后执行的操作
在执行各个阶段时,不论是 clean 周期,还是 default, site 周期, 执行后面的阶段,一定会把前面的阶段先执行。
即: 如果我们执行 mvn clean 命令, 就会把 pre-clean 阶段也执行,并且是优先于 clean 执行
mvc clean= mvc pre-clean clean 命令。
mvc post-clean= mvc pre-clean clean post-clean
故记住生命周期的阶段顺序是很有必要的。
一.二 default 生命周期
默认生命周期,是maven 的主要周期,主要用于对项目的 验证,编译,测试,打包,安装,部署 等主要的操作。
下面的这些命令太长,直接从 菜鸟教程的 Maven系列的 Maven 构建生命周期 一章摘录。 (菜鸟教程,一个很好的学习网站)
共 23 个阶段
生命周期阶段 | 描述 |
validate(校验) | 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。 |
initialize(初始化) | 初始化构建状态,比如设置属性值。 |
generate-sources(生成源代码) | 生成包含在编译阶段中的任何源代码。 |
process-sources(处理源代码) | 处理源代码,比如说,过滤任意值。 |
generate-resources(生成资源文件) | 生成将会包含在项目包中的资源文件。 |
process-resources (处理资源文件) | 复制和处理资源到目标目录,为打包阶段最好准备。 |
compile(编译) | 编译项目的源代码。 |
process-classes(处理类文件) | 处理编译生成的文件,比如说对Java class文件做字节码改善优化。 |
generate-test-sources(生成测试源代码) | 生成包含在编译阶段中的任何测试源代码。 |
process-test-sources(处理测试源代码) | 处理测试源代码,比如说,过滤任意值。 |
generate-test-resources(生成测试资源文件) | 为测试创建资源文件。 |
process-test-resources(处理测试资源文件) | 复制和处理测试资源到目标目录。 |
test-compile(编译测试源码) | 编译测试源代码到测试目标目录. |
process-test-classes(处理测试类文件) | 处理测试源码编译生成的文件。 |
test(测试) | test(测试) |
prepare-package(准备打包) | 在实际打包之前,执行任何的必要的操作为打包做准备。 |
package(打包 | 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。 |
pre-integration-test(集成测试前) | 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。 |
integration-test(集成测试) | 处理和部署项目到可以运行集成测试环境中。 |
post-integration-test(集成测试后) | 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。 |
verify (验证) | 运行任意的检查来验证项目包有效且达到质量标准。 |
install(安装) | 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。 |
deploy(部署) | 将最终的项目包复制到远程仓库中与其他开发者和项目共享。 |
1 .阶段很多啊,不需要我们全部忘记, 只需要记住一些常用的就可以了。
常用的有: validate,compile, test, package, verify,install, deploy
2 .我们运行后面的阶段,会自动将前面的阶段全部运行。
相对的,运行某个命令出错,不一定是这个命令千万了出错,也可能是前面的出错了。 如 运行 package 打包命令出错了,不一定说是 package命令一定出错了, 可以是前面的 compile 或者 test 出错了,导致后面的阶段无法运行。
3 .在运行的时候,可以同时运行一个生命周期的不同阶段,
如 mvn compile test, mvc compile package
这样的命令是可以的, 但不建议这么使用。
4 .Maven 在运行时,可以跨生命周期进行运行,如同时运行 clean周期和default 周期。
mvn clean package, mvn clean test 是完全可以的。
先进行清理,再进行打包, 先进行清理,再进行测试。
一.三 site 生命周期
用来创造新的报告文档和部署站点。
共有四个阶段:
1 .pre-site 执行一些需要在生成站点文档之前完成的工作
2 .site 生成项目的站点文档
3 .post-site :执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
4 . site-deploy: 将生成的站点文档部署到特定的服务器上
常用的是 site 和site-deploy.
二. 依赖
二.一 jar包依赖规则
有时候, 一个 jar包 不可能办成所有的事情,如文件上传的 common-fileupload.jar 包,只是完成了文件上传的部分,关于文件的复制之类的操作代码,并没有完成,而是依赖于 common-io.jar 包。 common-fileupload.jar 需要依赖于 common-io.jar包而存在, 即 如果你只添加了 common-fileupload.jar包,而不添加 common-io.jar包,那么系统会报错,报 ClassNotFoundException, 像这样的关系,叫做直接依赖。 项目A引用了项目B,那么项目B就是项目A的直接依赖。 有了直接依赖,那么就有间接依赖。项目A引用了项目B,而项目B又引用了项目C,那么项目C就是项目A的间接依赖。 当直接依赖和间接依赖多的时候,就容易出现问题。
在一个项目里面,有很多的框架组成,如小型的 SSM框架。 里面有很多的jar包, Spring直接依赖于 某些jar包,如 日志类的, MyBatis 直接依赖于某些 Jar包,也有日志类的, Spring直接依赖的jar包与MyBatis直接依赖的Jar包 可能会有重复, 那么这些重复的jar包,该导入哪些呢,是导入Spring的,还是导入MyBatis的呢? 这只是直接依赖,还有可能有间接依赖, 如Spring间接依赖的jar包,与MyBatis间接依赖的jar包有重复,该用哪些呢? 该用哪些,实际上就是制定一些规则。 Maven导入jar包时,会自动将其依赖的jar包导入进来,且各个依赖包不造成冲突,就是因为这些规则.
Maven的依赖规则有两个,也是符合现实情况的:
1 . 最短路径者优先原则
A直接依赖于B, B直接依赖于C, 那么A间接依赖于 C
B直接依赖于 D, C 直接依赖于D, A对D都是直接依赖,
那么A依赖于的是哪个 D呢?
就像走路一样, 走哪儿,能更快到 D呢? 当然是 A–B--D 的路径,而不是 A–B--C-D的路径。
所以, A最后用的是 B依赖的 D jar包。
2 . 先声明者优先原则
A直接依赖于B, B依赖于D, A间接依赖于D.
A直接依赖于C, C依赖于D, A 间接依赖于D.
A–B--D, A—C---D, 长度都一样,最短路径者优先原则不符合了。 这个是,谁先说去哪,就去哪。 即,用户者说走 A–B--D,那么就用 B依赖的 D, 用户者说走 A–C--D,那么就用 C依赖的 D. 用户说走哪,是默认根据 用户先声明的哪决定的。
在pom.xml 的依赖 <dependencies > </dependencies > 里面, 先放置哪一个,就用哪一个。 你先放置 B, 那么D就是 B里面的, 你先放置 C, 那么D就是C 里面的。 所以在放置 依赖时,有一定的顺序。
这两个原则, 是Maven 自己在找 jar包时依据的,与用户没有多大关系,用户不需要关心这个依赖规则,但必须要知道这两个依赖规则。
下面这一个,才是与用户有关的,且必须要劳劳记住的。
二.二 Jar包的依赖范围
测试的jar包,如 junit4.12, 只希望在代码测试的时候使用,不希望在布署项目的时候 把这个jar包放置上去,这样可以减少资源, tomcat的jar包, server-api.jar, jsp-api.jar 在代码编译的时候有用,但在布署项目的时候,是没有的用的,并且是不能 把这个两个 jar包放置到tomcat里面的,因为tomcat 里面有这两个 jar包,会造成冲突, 所以一定要把这两个jar包 给去掉。 那这种情况该怎么办呢? 配置的依赖 jar包要是有一定的 使用范围就好了, 就就是 依赖范围。
依赖范围有六种: compile, test, provided, runtime, import,system, 其中最常用的是 test 和provided,runtime
1 .complie 编译依赖, 是默认的依赖范围。 在main 目录下的代码可以访问这个范围下的依赖,即jar包。 test 目录下的代码也可以访问这个范围下的依赖。 布署到 tomcat下时, 要把这个依赖放置在 WEB-INF 下的 lib 文件夹里面。
2 . test 测试依赖,仅仅是测试使用的。 在main目录下的代码不能访问这个依赖, test 目录下的代码可以访问这个依赖, 布署到tomcat下时, 不会把这个依赖放置在 WEB-INF下的 lib文件夹里面。 如 junit 4.12 这个依赖。
3 .provided 提供依赖 在main目录下的代码可以访问这个依赖, test目录下的代码也可以访问这个依赖, 但在布署到tomcat下时,不会把这个依赖放置在 WEB-INF 下的lib文件夹里面。 如 servlet-api, jsp-api
4 .runtime 运行依赖。 main目录下的代码不能访问这个依赖, test目录下的代码可以访问这个依赖, 布署到tomcat下时,会把这个依赖放置在 WEB-INF 下的lib 文件夹里面。 如 jdbc 驱动
5 . import(导入依赖) 和system(系统依赖) 目前用不到,老蝴蝶也不知道,就不讲解了。
总结成一张图就是:
上面的这些,是直接依赖的范围。 还有间接依赖的范围。
A 直接依赖于B,间接依赖于 C,D,E, 如果C 为complie, 那么A可以使用, D为 test,E 为provided 那么 A不能使用。
二.三 手动排除依赖
在 二.一 讲解的依赖原则时, Maven会根据 最短路径者优先原则和 先声明者优先原则 两个原则,来决定选用哪个依赖。 但是,要保证一点,这两个依赖 的坐标,包括版本号 要完全一样, 这样Maven 才认为两个是相同的,才会选择其一。 但如果两个依赖的坐标,常见的是版本不一样,那么这个时候,Maven 就会把两个依赖都导入进来。 很显然,两个不同版本号的 jar包放在一起,很有可能会出现问题,所以就需要手动排除依赖了。
选中 pom.xml 文件, 选择第三个选项卡 Dependency-Hierarchy , 找到那个版本不一致的 jar包, 如 spring-beans
选中 Exclude Maven Artifact ,进行排除即可
查看 pom.xml 文件:
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>2.3.24</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
用 exclusion 进行排除依赖
这样在 struts2-spring-plugin 里面就不会有 spring-beans 这个 依赖了。
谢谢!!!