Maven 的 Scope 范围与 DependencyManagement

一、scope

  1. compile (v. 编译): 全流程都在;

  2. test: 比如 junit, 只出现在测试中;(仅测试)

  3. provided: 比如 servlet_api, 出现在编译时需要, 运行时由环境提供 (容器已有), 不打进 war 包, 最终都有包用; (租用不买)

  4. runtime: 比如 jdbc, devtools, 与compile类似,都会打进 war 包。出现的目的主要是环境需要,但写代码用不到 (购入不用) 就像项目投标需要资格证书。与 provide 区别主要如下:

能否 import编译run出现在 war 包中
compile1111
runtime11
provided11
  • 除了 provided ,其他的两个 scope 会传递(transitive)到 子pom

  • 常见的 scope 例子:

# tomcat 容器中也有servlet-api包,本地就不用打进war/jar包
<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>3.1.0</version>
	<scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
	<scope>provided</scope>
</dependency>

# 环境需要
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
  1. system:引用本地的jar包才会选择这个 scope
<dependency>
	<groupId>java.test</groupId>
	<artifactId>java.test-api</artifactId>
	<version>3.1.0</version>
	<systemPath>本地文件路径</systemPath>
	<scope>system</scope>
</dependency>

二、optional

<optional> 标签为 true 时(默认为 false),代表对继承了该坐标的子项目是可选特性。也就是不会被继承(好比 Java 中的 final 类不能被其他类继承一样)

  • <scope>provided</scope><optional>true</optional> 都不会传递到 子pom

optional 与 provided 的区别

  • <optional>true</optional><scope>provided</scope> 的区别:

使用 provided 的范围添加依赖项, 在逻辑上与使用 optional 标志添加依赖项不同. provided 的依赖将由我们模块的运行时环境提供, 在这种情况下没有可选功能. 请注意, 子项目再次添加了该依赖项, 范围也一定是 provider 的, 因为我们知道它将由项目的最终运行时环境提供

  • optional 表示依赖可选,该依赖是否使用都不会影响服务运行

  • provided 表示依赖必须但通常是由最终运行时 (系统或者容器) 提供, 不需要添加到 jar 包

optional: 吃面时的酱油, 不加也不会影响 (注意, 如果去掉影响子项目, 则表示不适合用 optional )
provided: 吃面时的筷子, 这样的东西都是必须的, 不过一般店家给顾客备好了, 不需要顾客自带

  • 常见的 optional 例子:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

我的理解是, 他们都起一样的效果仅在语义上有所区别.

  • optional: 如果我提供了4种数据库的访问方式, 但实际使用只需要其中一种 (将选择交给别人来决定) , 比如 spring-boot-configuration-processor

  • provided: 如果这个功能只是起辅助作用, 并不会给别人用. 比如说 lombok 类似于这些插件, 他们生成代码和配置后, 就不再使用.

三、DependencyManagement

  1. <dependencyManagement> 预定义了依赖版本,在 dependency 使用时就可以不用 scope 和 version;
  2. 子模块引用父类 pom 的 <dependencyManagement> 必须设置 scope 为 import;
  3. dependencyManagement,只在被 dependency 使用时才会导包。这种只引入需要的依赖方式也称为 “按需继承”;

四、scope 为 import

import
This scope is only supported on a dependency of type pom in the section. It indicates the dependency to be replaced with the effective list of dependencies in the specified POM’s
<dependencyManagement> section. Since they are replaced, dependencies with a scope of import do not actually participate in limiting the transitivity of a dependency.

  1. 当导入的模块没有 <scope>import</scope> 时,会将父模块所有的普通dependency全部继承到当前工程 dependencyManagement 中,并且会传递依赖。
  2. 有 <scope>import</scope> 继承的是 dependencyManagement;
  3. 没有 <scope>import</scope> 继承的是 dependency(也称为普通 dependency);
  4. 注意:在 dependencyManagement 中,scope = import 只能用于 type = pom 的 dependency 里;
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-dependencies</artifactId>
	<version>${spring.boot.version}</version>
	<type>pom</type>
	<scope>import</scope>
  1. 大家使用 ide 点进 artifact 里面,看依赖内容是写在那里的就行了。写在 management 里面就加一条 import,如果是写在 dependency 里面,就不加,最终都会成为本 pom 的 dependencyManagement。

五、type

  1. <dependency>中 type 默认为 jar,即引入一个 jar 包。因为 pom 中大量的 jar 包会造成导的包过多过大,显得特别混乱。所以设置 type 为 pom,maven 就会将里面的所有的 jar 包打包成一个 pom,然后依赖 pom(即含有所有依赖的jar包)
  2. 当 type 不为 jar 时,必须写上 <type> 标签;
  3. pom 对应 <packaging>pom<packaging>
  4. type 还有其他类型,比如 war、bar、apk、ejb 等,仅供了解。

六、插件

  • mvn 命令本身不会执行任何功能,实际干活的是插件;

  • maven 并不会直接调用插件;

  • maven 是通过 pom 文件里的 <plugin> 标签,绑定插件的坐标,再根据里面的<execution>定义的 goals 和 phase 来干活的;

  • n:n关系:插件和 Maven

    • 插件里可以有多个 goal
    • maven.lifecycle.phase 可以绑定一个或多个 goal
  • 插件的功能是通过 maven 的生命周期(lifecycle)顺序执行周期(phase)触发周期绑定的插件里的 goal 来实现的;

  • Maven 会根据 packaging 默认绑定了一些自带的插件,无显示需引用;比如执行 mvn clean 会执行 maven-clean-plugin 插件下的 goal: clean

  • packaging 为 jar 时(不写默认为 jar ),执行mvn package 才默认绑定具体打包插件。

  • 深入了解可以查看我的另一篇文章:如何编写 Maven 插件

七、Goal

执行的Phase对应执行的Goal
compilecompiler:compile
testcompiler:testCompile
surefire:test
  • 使用方法:mvn [plugin-name]:[goal-name]
    e.g. mvn compiler:compile
    在这里插入图片描述
  • SpringBoot 打包插件会把自己绑在 package 这一步了,Maven 执行到 package 这一步就会自动调用这个插件;(之所以没有写 execution 是因为,继承了 parent :spring-boot-parent,在父 pom 中,已经默认定义了)
    在这里插入图片描述

八、生命周期

  • maven的有非常多生命周期,如pre-clean、clean…到site、post-site、site-deploy等,但实际使用的是少数几个周期;
  • 这些周期(phase)多个一组,分为三套生命周期(每套lifecycle下面都有一些细分的phase:pre-、post-)
    • clean 周期:清理项目(“clean周期”是一套,包含“clean” phase)
    • default 周期:主体周期,构建…
    • site 周期:建立站点,部署到服务器

从实际使用角度理解(实际的作用):

  • 火车(lifecycle)、车厢(phase)、货品(goal),货品(goal)可以放在任何一列火车(lifecycle)的任何车厢(phase),一列火车(lifecycle)包含多节车厢(phase),车厢(phase)是有顺序的,货品按照从前往后摆放(绑定)顺序。
  • 火车(lifecycle)只有三辆:clean、default、site
  • 执行mvn clean package 执行的是 phase,对比下表实际发生的就是让clean火车(lifecycle)开到clean(phase),执行了两步:pre-clean、clean;然后让default火车(lifecycle)开到package(phase),执行了n步;
  • 详细的生命周期 lifecycle(顺序)

    • clean(3个):
      pre-clean, clean, post-clean
    • default(23个):
      validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy
    • site(4个):
      pre-site, site, post-site, site-deploy
  • maven 命令

mvn [options] [<goal(s)>] [<phase(s)>]
  • The typical invocation for building a Maven project uses a Maven life cycle phase. E.g.
mvn verify

九、properties

可以自定义一个或多个 maven 属性,然后在 pom.xml 里使用 ${属性名} 引用。
maven 总共有 6 类属性:内置属性、POM属性、自定义属性、Settings属性、java系统属性和环境变量属性

  1. 内置属性(两个常用内置属性)

${basedir} 表示项目跟目录,即包含 pom.xml 文件的目录;
${version} 表示项目版本

  1. pom 属性

用户可以使用该类属性引用POM文件中对应元素的值。如${project.artifactId}就对应了<project> <artifactId>元素的值,常用的POM属性包括:

${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/

${project.build.testSourceDirectory}:项目的测试源码目录,默认为src/test/java/

${project.build.directory} : 项目构建输出目录,默认为target/

${project.outputDirectory} : 项目主代码编译输出目录,默认为target/classes/

${project.testOutputDirectory}:项目测试主代码输出目录,默认为target/testclasses/

${project.groupId}:项目的groupId

${project.artifactId}:项目的artifactId

${project.version}:项目的version,与${version} 等价

${project.build.finalName}:项目打包输出文件的名称,默认为${project.artifactId}-${project.version}
  1. 自定义属性

最好理解的属性;

  1. settings属性

与 pom 属性同理,用户使用以 settings. 开头的属性引用 settings.xml 文件中的 XML 元素的值

  1. Java系统属性

所有 java 系统属性都可以用 maven 属性引用,如 ${user.home} 指向了用户目录

  1. 环境变量属性

所有环境变量属性都可以使用以 env. 开头的 maven 属性引用,如 ${env.JAVA_HOME} 指代了 JAVA_HOME 环境变量的的值

十、聚合(包含)与继承的关系

  1. 继承不等于聚合(包含)

  2. 聚合主要是为了方便快速构建项目,继承主要是为了消除重复配置

  3. 对于聚合模块而言,它知道有哪些被聚合的模块,但那些被聚合的模块不知道这个聚合模块的存在;对于继承的父pom 而言,它不知道有哪些子模块继承它,但那些子模块都必须知道自己的父pom 是什么

  4. 聚合pom 与继承中的父pom 的 packaging 都必须是 pom;同时,聚合模块与继承中的父模块除了 pom 外,都没有实际的内容

  5. 插件的传播 (inherited) 与继承

    1. POM 中的任何元素都会被继承
    2. 插件也不列外,但可以重写子模块插件的configurationskip 等于 true,表示在本模块中跳过执行该插件。
    3. 无法中止继承,但插件的配置信息可以中止传播或者使用 pluginManagement 然后手动调用
  • 设置本插件跳过执行
<build>
	<plugins>
		<plugin>
			<g>..<a>..<v>..
			<configuration>
				<skip>true</skip>
			</configuration>
  • 中止传播配置
<build>
	<plugins>
		<plugin>
			<groupId>com.spotify</groupId>
			<artifactId>dockerfile-maven-plugin</artifactId>
			<version>1.4.10</version>
			<executions>
				<execution>
					<!--配置不会被传播到子POM -->
					<inherited>false</inherited>
					<id>default</id>
					<goals>
						<goal>build</goal>
						<goal>push</goal>
					</goals>
				</execution>
			</executions>
			<!--任何配置 都不会被传播到子项目 (不填默认为true, 默认为传播) -->
			<inherited>false</inherited>
			<configuration>
				<skip>false</skip>
				<repository>10.8.206.107:5000/${project.artifactId}</repository>
			</configuration>
		</plugin>
	</plugins>
</build>
  • 如同可以设置 -Dmaven.test.skip=true ,我们也可以在不想继承的父模块内加上<插件名.skip>true</>,然后在configuration里面设置skip为false:
<properties>
	<!--这里 dockerfile 是插件名称-->
	<dockerfile.skip>true</dockerfile.skip>
</properties>

<build>
	<plugins>
		<plugin>
			<groupId>com.spotify</groupId>
			<artifactId>dockerfile-maven-plugin</artifactId>
			<version>1.4.10</version>
			<configuration>
				<!--加上本模块跳过为false-->
				<skip>false</skip>
				<repository>10.8.206.107:5000/${project.artifactId}</repository>
			</configuration>
		</plugin>
	</plugins>
</build>

十一、POM 的四层体系

超级POM - 父POM - 当前POM - 有效POM (effective pom)

  • 超级POM的位置:${MAVEN_HOME}/lib/maven-model-builder-3.0.4.jar,打开该文件,能找到超级POM:\org\apache\maven\model\pom-4.0.0.xml,它是所有Maven POM的父POM,所有Maven项目继承该配置。

  • 查看当前有效pom的命令:mvn help:effective-pom

  • 查看当前项目的所有mvn配置 mvn -X

  • 打印所有可用的环境变量和Java系统属性 mvn help:system

  • 生成新pom命令:mvn archetype:generate

  • 查看依赖树:mvn dependency:tree

  • Maven 有哪些元素(一层)

    • groupId
    • version
    • description
    • organization:组织信息;
    • inceptionYear:项目的创始年份;
    • url :项目的 url 地址
    • develoers:项目的开发者信息;
    • contributors:项目的贡献者信息;
    • distributionManagerment:项目的部署信息;
    • issueManagement:缺陷跟踪系统信息;
    • ciManagement:项目的持续继承信息;
    • scm:项目的版本控制信息;
    • mailingLists:项目的邮件列表信息;
    • properties:自定义的 Maven 属性;
    • dependencies:项目的依赖配置;
    • dependencyManagement:醒目的依赖管理配置;
    • repositories:项目的仓库配置;
    • build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等;
    • reporting:包括项目的报告输出目录配置、报告插件配置等。

十二、版本仲裁

同级先声明用谁,不同级谁近用谁。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值