maven 核心概念速成教程

结论先行,本文先给出一些结论总结,然后再以spring-boot为例,给出在实际生产中对maven使用上的最佳实践,最后再给出maven相关的一些关键知识提炼,感兴趣的可以再看看参考内容。

一些总结

  1. import只作用于dependencyManagement,不会作用于pluginManagement以及properties等其他元素,这是与parent继承的最大区别。
  2. scope可以理解为不同的环境,在java中,不同的环境其实就是不同的class path,即每个scope都有各自的class path。
  3. 对于scope而言,具有传递性依赖的scope只有compile与runtime这两者。
  4. optional只作用于传递性依赖,为true时,表示不具传递性。

Maven最佳实践

  1. parent以及import的使用

对于一个项目的group,通常有两个主要的pom,一个为{group-name}-dependencies.pom另一个则是{group-name}-parent.pom。其中dependencies pom主要用于对dependencyManagement的管理,parent pom则是对于properties、plugin的pluginManagement、repository等元素的统一管理。这样,对于使用者而言,可以直接import {group-name}-dependencies的pom来进行依赖管理,而用可以继承自己的parent pom。

以spring boot为例,spring-boot是该整个项目的group名字,spring-boot-dependencies里管理了所有需要使用到的dependencyManagement以及pluginManagement,然后spring-boot-parent则以spring-boot-dependencies为parent,从而继承了dependencies、pluginManagement以及那些properties。

spring-boot有些特例,通常是以{group-name}-parent.pom为根,然后在dependencyManagement里import {group-name}-dependencies.pom,这样可以讲parent pom与dependencies pom的职位分开,dependencies pom只负责依赖的dependencies management。

  1. bom的使用

对于大型项目,通常有多个项目,对于这些项目的依赖以及一些参数都需要统一管理,为此可以定义一个最基础的pom作为所有项目pom的parent。以此,一方面可以减少项目的配置量,另一方面,对依赖的版本控制以及其他元素如repository、plugin都能统一控制。

  1. 何时使用provided

provided的含义是我需要的jar包会在运行时有运行时环境提供。比如我们在写一个依赖于spring mvc的拦截器interceptor,那么我们可以对于spring mvc的依赖设为provided,因为我们认定你是在spring mvc的时候才会使用这个jar包,否则你是不会使用的。通过对jar的依赖设置成provided,可以有效避免jar包冲突以及包变的很大,通常在书写common包(即提供给他人使用的jar包)时要注意对于依赖引入的慎重,尽可能的设置为provided

一种特殊情况是lombok(一种简化getter、setter书写的工具包),它的scope通常也为provided,但并不是因为运行时环境提供,而是因为lombok只需要在编译时使用。

  1. 何时使用optional

通常不会使用这个功能,即使是写common包,也很少使用,因为一旦设置为optional,但是调用方没有提供这个jar包,就会导致运行时失败,但编译不会失败,所以很危险。使用optional的情况,只有是在采用类似SPI机制时,具体使用哪类jar包由调用方决定,例如是mysql或者orcale的driver。通常这类jar的scope是runtime。

Maven介绍

对于java程序员,必不可少的是代码的构建(build)工具,maven作为一款优秀的构建工具广为人知。他的“惯例优于配置”的理念,即CoC(Convention over Configuration),以及包的传递依赖管理,大大简化了以前用ant对jar包依赖管理的麻烦。以下省略N字,具体可参考官网https://maven.apache.org/。

Maven默认包管理方案

在使用maven的时候,经常遇到包的版本冲突,除了使用exclusions的方法外,了解maven默认的管理策略也很重要。

  • 优先按照依赖管理元素中指定的版本声明进行仲裁,此时下面的两个原则都无效了
  • 若无版本声明,则按照“短路径优先”的原则(Maven2.0)进行仲裁,即选择依赖树中路径最短的版本
  • 若路径长度一致,则按照“第一声明优先”的原则进行仲裁,即选择POM中最先声明的版本

注意:maven的默认管理是不会根据包的版本来判断的,以为maven会默认选择最新版本的包,这是一个误解。

Maven的scope与依赖概念

除了在使用包的时候要注意包依赖的版本管理,在我们编写jar包给他人使用时,更需要了解maven对包管理的机制,以此可以写出方便他们使用的jar,不合理的jar依赖会大大增加包管理的复杂度。

由于maven创新的利用包的传递依赖来解决使用者引入包的麻烦,所以对于一个jar的引入具有两种依赖,一个是直接依赖,另一个则是传递依赖

为了对这两种依赖进行控制,maven引入了scope的概念,来针对不同环境时引入不同的依赖,分别有:compile(默认),provided,runtime,test,system。

在介绍这五种scope之前,需要讲一下maven环境这一概念,maven有三种环境,分别为编译环境、测试环境、运行环境,与maven命令的对应关系为:maven compile - 编译环境;maven test - 测试环境;maven package及其以上步骤 - 运行环境。所谓环境,可以理解为我们在使用java、javac等命令时引入的classpath。scope分别对应着这三种环境,即影响范围

  • compile:在所有的环境(classpath)中生效,同时它们也会被打包。

  • provided:顾名思义“已提供”,指所依赖的这个jar在使用时会被外部环境
    所提供,自身不需要提供,所以只在编译环境中的classpath生效,测试与打包时都不会被引入。例如, 你开发了一个web 应用,你可能在编译 classpath 中需要可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API,因为这个Servlet API会由Web 容器提供。

  • runtime:顾名思义,只在运行环境(classpath)中生效,在编译时不会生效,只在打包的时候会被引入。比如,你可能在编译的时候只需要JDBC API JAR,而只有在运行的时候才需要JDBC
    驱动实现。

  • test:在一般的编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用。

  • system:该scope不推荐使用,基本可以忽略。顾名思义,系统,指的是这个包是在本地系统会有所提供。与provided 类似,但是你必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,你必须同时提供一个 systemPath 元素。

Maven传递依赖与optional

maven的scope除了定义了直接依赖还有使用范围,同时也间接指定了传递依赖的关系:

  • compile:编译、测试、运行环境都会有传递依赖。
  • provided:无传递依赖。
  • runtime:测试、运行环境有传递依赖。
  • test:无传递依赖。
  • system:同provided,无传递依赖。

除了scope规定的传递依赖,为了更方便的处理compile与runtime的传递依赖,maven还提供了optional的关键字,默认为false,当指定为true时,表明这个依赖是可选的。所谓可选,指的是存在多个可选的依赖包,比如数据库驱动包,有oracle的、mysql的,等等。采用optional,表明由使用者决定该使用哪个包。optional通常用于runtime的scope。

Maven的聚合与继承概念

聚合继承都会为了编写多个包时候的方便使用。按照maven“惯例优于配置”的原则,通常一个maven对应于一个project。但很多时候一个project需要多个jar来组合,来方便分层管理,使得每个层只管理自己的功能。例如一个常见的web项目,分为了dal、service、api三个层次的jar包。为此,maven引入module(模块)的概念,来便于管理多个jar包(子项目)在一起的情况。为了方便对多模块项目的管理,我们通常会利用maven聚合继承的功能。

  • 聚合
    对于多个模块,默认需要进入每一个模块内再进行编译,为了方便使用,可以在模块外围建立一个pom,然后对每个模块以<module></module>的方式引入,这样就可以在模块外围对所有模块一次性编译、运行。
  • 继承
    由于很多项目pom的元素内容是可以复用的,所以为了方便使用pom,可以通过继承pom来减少通用元素内容的编写,即maven的parent元素。同时,通过利用parent,可以实现一套统一规范的版本控制,避免各个项目引入不同的包版本,导致包的版本泛滥。

通常继承与聚合是一起使用的,即一个项目的pom是聚合,同时也是parent,即内部的模块都以此pom为parent。

参考

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值