maven笔记

1 maven可以作为一个构建工具,定义了构建工程的一般接口

2 Maven 的核心其实不做什么实际的事情,除了解析一些 XML 文档,管理生命周期与插

件之外,它什么也不懂。Maven 被设计成将主要的职责委派给一组 Maven 插件,这些

插件可以影响 Maven 生命周期,提供对目标的访问。绝大多数 Maven 的动作发生于

Maven 插件的目标,如编译源码,打包二进制代码,发布站点和其它构建任务。

3 maven定义的项目模型

  • 依赖管理。由于项目是根据一个包含组标识符,构件标识符和版本的唯一的坐标定义的。项目间可以使用这些坐标来声明依赖。
  • 远程仓库。和项目依赖相关的,我们可以使用定义在项目对象模型(POM)中的坐标来创建Maven 构件的仓库。
  • 全局性构建逻辑重用。插件被编写成和项目模型对象(POM)一起工作,它们没有被设计成操作某一个已知位置的特定文件。一切都被抽象到模型中,插件配置和自定义行为都在模型中进行。
  • 工具可移植性/集成。像 Eclipse,NetBeans,和 InteliJ 这样的工具现在有共同的地方来找到项目的信息。在Maven 出现之前,每个 IDE 都有不同的方法来存储实际上是自定义项目对象模型(POM)的信息。Maven 标准化了这种描述,而虽然每个 IDE 仍然继续维护它的自定义项目文件,但这些文件现在可以很容易的由模型生成。
  • 便于搜索和过滤构件。像 Nexus 这样的工具允许你使用存储在 POM 中的信息对仓库中的内容进行索引和搜索。

4 groupId,artifactId, packaging, version——是Maven的坐标(coordinates)

5 第一次运行maven会从远程maven库下载很多插件,插件只有在需要的时候才会触发下载

6 maven install用于把远程仓库的构件下载到本地仓库,这样才能被使用。

mavne clean用于移除旧的输出,保证执行干净构建。

7 maven使用了传递性依赖,一个复杂的项目将会包含很多依赖,也有可能包含依赖于其它构件的依赖。假如你的项目依赖于一个库,而这个库又依赖于五个或者十个其它的库(就像Spring或者Hibernate那样)。你不必找出所有这些依赖然后把它们写在你的pom.xml里,你只需要加上你直接依赖的那些库,Maven会隐式的把这些库间接依赖的库也加入到你的项目中。Maven也会处理这些依赖中的冲突,同时能让你自定义默认行为,或者排除一些特定的传递性依赖。

maven在下载构件的时候,会同时下载构件的pom文件,以此来实现传递性依赖。

8 maven提供了依赖的范围概念,比如test,只有运行测试命令的时候才会依赖进去;比如provided,当你

开发web应用的时候provided范围变得十分有用,你需要通过Servlet API来编译你的代码,但是你不希望Servlet API的JAR文件包含在你web应用的WEB-INF/lib目录中

9 构建大型项目的问题,依赖优化。

 

  • 上移共同的依赖至dependencyManagement。如果多于一个项目依赖于一个特定的依赖,你可以在dependencyManagement中列出这个依赖。父POM包含一个版本和一组排除配置,所有的子POM需要使用groupId和artifactId引用这个依赖。如果依赖已经在dependencyManagement中列出,子项目可以忽略版本和排除配置。
  • 为兄弟项目使用内置的项目version和groupId。使用{project.version}和org.sonatype.mavenbook来引用兄弟项目。兄弟项目基本上一直共享同样的groupId,也基本上一直共享同样的发布版本。使用0.6-SNAPSHOT可以帮你避免前面提到的兄弟版本不一致问题。
  • 如果直接使用到某个构件,尽可能使用显式依赖。当一个项目使用一些被使用的类库如Jakarta Commons Beanutils。你没有显式的声明对Beanutils的依赖,你的项目依赖于一个项目如Hibernate,而后者有对Beanutils的传递性依赖。你的项目可能编译成功并很好的运行,但当你将Hibernate升级到一个新版本,而它不再依赖于Beantuils,你就会遇到编译和运行错误了,这种情况直到项目不能编译才能显现。同时,由于你没有显式的列出依赖的版本,Maven不能帮你解析可能出现的版本冲突问题。防止传递性依赖因升级出问题,使用这个命令可以检测出来mvn dependency:analyze

[WARNING] Used undeclared dependencies found:

[WARNING] javax.persistence:persistence-api:jar:1.0:compile

当出现这个的时候,就需要显式依赖声明了。

10 依赖范围

 

  • compile(编译范围)。compile是默认的范围;如果没有提供一个范围,那该依赖的范围就是编译范围。编译范围依赖在所有的classpath中可用,同时它们也会被打包。
  • provided(已提供范围)。provided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。例如,如果你开发了一个web应用,你可能在编译classpath中需要可用的Servlet API来编译一个servlet,但是你不会想要在打包好的WAR中包含这个Servlet API;这个Servlet API JAR由你的应用服务器或者servlet容器提供。已提供范围的依赖在编译classpath(不是运行时)可用。它们不是传递性的,也不会被打包。
  • runtime(运行时范围)。runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC驱动实现。
  • test(测试范围)。test范围依赖 在一般的 编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。
  • system(系统范围)system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个systemPath元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的Maven仓库中引用依赖)。

11 继承于一个父项目和被一个多模块项目管理是有区别的。一个父项目是指它把所有的值传给它的子项目。一个多模块项目只是说它管理一组子模块,或者说一组子项目。多模块关系从上层往下定义。当建立一个多模块项目的时候,你告诉一个项目它的构建需要包含指定的模块。多模块构建用来将模块聚集到一个单独的构建中。父子关系是从叶节点往上定义的。父子关系更多的是处理一个特定项目的定义。当你给一个子项目关联一个父项目的时候,你告诉Maven该项目的POM起源于另一个项目。

 

 12 由于传递性依赖的特性,不可避免的会出现依赖包的版本冲突。maven自身的仲裁机制有:

  • 浅路径优先
  • 加载顺序优先
  • 覆写优先,即子pom优先
  • 声明优先,即在dependencyManagement中声明版本号

如果不通过这几个仲裁机制解决的话,那么可以采用exclude特性,排除多余的间接依赖

 

13 maven项目打包时,如果依赖构件是属于项目自身的模块,那么会直接使用本地项目的代码打包,而不是去远程仓库下载。

 

 

你可能感兴趣的:(maven)