一、缘起
在前面写了一篇《Maven打包SpringBoot项目,排除第三方依赖包》,写的过程中,又再次与maven占位符这个问题重逢了。说到重逢,是因为在很早之前,我刚搭建spring boot项目的时候,就栽在这个坑里了。那是只是浅显的知道spring boot 偷偷摸摸地把maven的默认占位符给修改了,但是,没有去深入的理解。现在,回过头来,梳理一遍。
二、运行环境
操作系统:Windows 10 ;
开发工具:IDEA-2019.3;
Web服务器:Tomcat 9.0.24;
JDK版本: jdk 1.8.0_221;
Maven版本:apache-maven-3.6.1
Spring boot 版本:2.0.9.RELEASE
三、原理分析
工欲善其事,必先利其器。想要把功能做好,就要先明白背后的原理。原理理解清楚了,实际操作可谓是手到擒来。
说到maven的占位符,其实并不准确。这也是一直让我混淆的概念。
我们分开来讲:
- maven中有很多内置变量,具体有哪些变量,可以参考https://www.jianshu.com/p/ded7dfa2c3d8。比如,basedir表示项目根目录,version表示项目版本。而这些变量如何使用呢,就是使用占位符了,如
${version}
。这里的占位符就是${ }
。这里是maven默认的,而这个占位符使用的场景,也就是在pom.xml之中。这里的占位符,我几乎没有见过要去修改的。 - 而通常意义上说的,其实是maven的
maven-resources-plugin
插件中的一个配置项<delimiter>${resource.delimiter}</delimiter>
。翻译过来,是定界符的意思。中文互联网太多以讹传讹和一知半解了。那么,这个只是一个小小插件的配置项,为何就上升到了好像成了一个maven的一个配置呢?
首先,就是这个定界符和上面的变量占位符长的一毛一样,这不就是故意让人混淆的嘛;其次,还要从maven-resources-plugin
这个插件本身的功能和特别之处说起了。
Resources插件负责处理项目资源文件并拷贝到输出目录。Maven将main resources和test resources分开,一般main resources关联main source code,而test resources关联test source code。
这有啥特殊的呢?看一下官方的这句话:
Starting with version 2.3 this plugin uses the Maven Filtering shared component for filtering resources.
就是说呢,从2.3版本开始,resources插件可以实现过滤资源了。这里过滤的名称起的不好,其实,可以说预编译,或者是替换。就是把定界符里的变量用真实的值替换掉。
这里定界符一般定义在src/main/resources
目录下的文件中,而真实的值可以是maven内置变量,<properties>中定义的变量,或者是<filter>过滤器中引用的文件中的变量值。这里是否启用过滤功能,也是可以配置的。说这么多有啥用呢?这个主要就是用在项目多环境配置中。
五、总结
寻找资料,来来回回还都是官方文档是最权威的。本身基础不牢固,就要把基础打牢靠才可以。
六、附录
- maven resources插件官方地址:http://maven.apache.org/plugins/maven-resources-plugin/index.html
- maven filter功能官方地址:http://maven.apache.org/shared/maven-filtering/
- maven 父子模块的插件传递机制
maven子模块可以通过继承获得的pom中元素有:
- properties:自定义的Maven属性
- dependencyManagement:项目的依赖管理配置
- build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
- maven 中的resoures插件
resoures插件,是maven默认绑定的插件,所以,不用显式的引入。这里还是我的知识盲点,到底是如何引入的,我还没有弄清楚。 - spring boot 中 定界符的配置
官方文档:“How-to” Guides => 2. Properties and Configuration => 2.1.1. Automatic Property Expansion Using Maven:
If you inherit from the
spring-boot-starter-parent
POM, the default filter token of themaven-resources-plugins
has been changed from${*}
to@
(that is,@maven.token@
instead of${maven.token}
) to prevent conflicts with Spring-style placeholders. If you have enabled Maven filtering for theapplication.properties
directly, you may want to also change the default filter token to use other delimiters.
上面是官方的文档。大概意思就是说,因为maven的定界符和spring自身的属性配置的占位符冲突了,所以,spring boot中把maven的定界符改成了@,而spring自己还是使用${}。
- 父(Super)POM
父(Super)POM是 Maven 默认的 POM。所有的 POM 都继承自一个父 POM(无论是否显式定义了这个父 POM)。父 POM 包含了一些可以被继承的默认设置。因此,当 Maven 发现需要下载 POM 中的 依赖时,它会到 Super POM 中配置的默认仓库 http://repo1.maven.org/maven2 去下载。
Maven 使用 effective pom(Super pom 加上工程自己的配置)来执行相关的目标,它帮助开发者在 pom.xml 中做尽可能少的配置,当然这些配置可以被重写。
使用以下命令来查看 Super POM 默认配置:
mvn help:effective-pom
上面这段话,是我摘抄自https://www.runoob.com/maven/maven-pom.html的,因为说的太好了。完美解释了maven构建的底层逻辑和思想。给我解了惑。
但是上面去默认仓库下载的路径是打不开的。我找了一下,可以在这个路径找到:http://maven.apache.org/ref/3.0.4/maven-model-builder/super-pom.html
- Maven的几个核心概念
生命周期(lifecycle):maven将构建项目的过程进行了抽象,抽象出来了一个过程,这个过程被称作生命周期(lifecycle)。lifecycle是有多个有序的阶段(phase)构成的。
阶段(phase):maven将lifecycle划分为多个有序的过程(step),每一个过程被称作一个阶段(phase)。
目标(goal):goal在maven中是真正执行任务的单元,goal的提供者是插件(plugin),每一个plugin可能提供多个goals。例如 mvn compiler:compile表示了一个goal,其提供者是插件 compiler。compiler其实是这个插件的缩写,其完整的插件名字为org.apache.maven.plugins:maven-compiler-plugin,compile仅仅是这个一个插件中的一个goal。
三者之间的管理:goal是一个执行任务的最小单元,每一个goal都是由其对应的plugin提供的;可以将对应的goal绑定到某个phase上,当在进行maven构建的过程中只要执行到了对应的phase上,就可以在当前phase上完成goal的执行。