# maven * ## maven的pom文件结构 * project:project元素是pom文件的顶层元素 * modelVersion:pom文件使用的model版本 * groupId * artifactId * version * name:maven项目的名称 * url:项目的url资源路径 * propertities:包含可以在pom文件中任何位置访问的变量 * dependencies:定义该项目使用的依赖项 * build:定义项目的目录结构和插件的管理 * packaging:指明项目打jar包还是war包 * ## maven命令 * mvn compile:会对项目进行编译,并且将编译后的字节码放置到basedir/target/classes目录下 * mvn test:对项目的main源码进行编译,并且再对test源码进行编译,并执行单元测试 * mvn package:编译项目并且创建jar包,创建的jar包将会被放置到basedir/target目录下 * mvn install:生成项目对应的jar包并且将生成的jar包安装到本地仓库中(homedir/.m2/repository) * mvn clean:再开始前移除target目录中所有的文件 * ## SNAPSHOT * < verssion >标签值中含有snapshot代表该artifact版本并不是稳定或者不变的,而是一个快照版本,是可能被修改的 * ## plugin使用 * 当想对项目的构建过程进行自定义时,需要再pom文件的build标签中添加plugin: ```pom org.apache.maven.plugins maven-compiler-plugin 3.3 1.8 1.8 ``` * ## 向maven项目中添加资源 * 如果想要向maven项目中添加资源,那么将资源复制到basedir/src/main/resources或者basedir/test/main/resources目录下,在项目生成jar包时,会将资源复制到jar包中的classpath目录下 * ## maven项目添加依赖 * 通过向pom文件中添加dependency可以为项目添加依赖项 * 依赖至少需要有如下元素: * groupId * artifactId * version * scope可选:指定依赖的作用范围 * compile * test * runtime * ## maven项目中parent * 可以为父maven项目指定modules来指定子项目 * 可以为子项目指定parent元素来指定父项目 * 可以在父项目的路径下调用mvn package同时打包多个项目 * ## maven filtering * 通过filter,可以在资源文件中使用${}来引用环境变量、定义在pom文件中的变量、定义在外部文件中的变量(需要在filters中指定)、在命令行中通过-D指定的变量 * 在对资源文件实施filering时,需要指定资源文件路径,并且在resource标签中将filtering属性指定为true * ## maven生命周期 * maven项目的生命周期分为如下三种 * default lifecycle * clean lifecycle * site lifecycle:负责web项目的建立和发布 * maven项目的default生命周期: * validate:验证项目是否正确 * compile:编译源代码 * test:通过单元测试来对编译好的源代码进行测试 * package:将编译好的源码进行打包,打包成jar包或者是war包 * verify:对集成测试的结果进行检查 * install:将打包后的结构安装到本地仓库中 * deploy:在构建环境中完成,将软件包部署到远程仓库中 * 当调用上述生命周期的命令时,只需要调用最后一个阶段名称,之前的阶段会被默认执行(eg:如果调用mvn package,那么之前的阶段例如validate、compile、test、package也会被默认执行) * 如果在调用生命周期命令之前想要清理先前的残留,可以在生命周期之前加入clean命令清理先前留下的target目录,eg:mvn clean package * maven的build阶段由plugin goals构成 * 每个plugin goal都会绑定到0或者多个build phase * 每个build phase都绑定了0或者多个plugin goals,如果一个build phase没有绑定plugin goals,那么它将不会被执行,如果绑定了多个plugin goals,多个plugin goals都会被执行 * ## maven的打包方式 * 已知build phase由多个plugin goal组成,那么,在构建项目时,为了将plugin goal和build phase相绑定,可以通过packaging标签指定打包的方式(如jar,war,pom,ear(除了包含war、jar包外,还包含EJB组件) * 如果指定packaging标签的打包方式为jar,那么maven项目将会为每个build phase都指定一个plugin goals列表;而对于打包成pom的项目,只会为install和deploy的阶段绑定plugin goals * ## maven插件 * maven通过plugin来提供plugin goals,plugin类似于dependency,也具有groupId,artifactId,version。plugin可包含多个plugin goals,并且可以为插件指定executions来指定执行的goal,并且可以指定phase将goal与build phase相关联。 * ## pom文件的继承关系 * 可以通过为子module中的pom文件指定一个parent元素来指定它的父pom文件。此时通常要求父parent已经安装在本地仓库后者父pom文件位于子module pom文件的上一级目录。 * 如果不满足上述条件,可以通过为parent元素指定relativePath来显式指定父pom文件的位置 * 可以为父pom指定modules元素,并将父pom文件中的packaging元素指定为pom,此时对父module调用mvn命令时,相同的命令会被传递给子module执行 * 子项目pom文件在继承父项目pom文件时,可以省略groupId和version,省略的内容会被自动填充为与父项目中pom文件定义的相同 * ## maven profile的激活方式 * 通过命令行激活:可以在mvn命令中指定-P选项,并且在之后跟上profile的id名称来指明激活的profile,-P后跟随的profile将会和activeProfiles中指明的pofile一起被激活 * 通过activition配置激活:在配置文件中,可以通过在profile标签中指定activition属性来指定激活条件 * 可以通过jdk版本前缀选择是否激活: ```pom 1.8 ``` * 可以通过os标签指定特定操作系统环境来选择是否激活 * 可以通过property来通过系统属性判断是否激活,可以通过命令行-D来添加参数控制是否激活(系统环境变量可以通过env.XXX来获取) * 可以通过文件是否存在(file标签的exists和missing)来判断是否激活 * activationByDefault:可以通过该标签来决定profile是否被激活 * 但是如果在同一pom文件中,有其他profile被上述的激活方法激活,那么默认被激活的profile将不会被激活 * 如果同一个pom文件中的其他profile通过命令行或者上述提到的其他方式被激活,那么所有默认激活的profile都不会被激活 * deactive一个profile:可以通过-P !profilename来不激活一个profile * profile定义的位置: * 外部文件(位于pom文件之外的文件,例如settings.xml或者profiles.xml)只能定义repositories、pluginRepositories、properties属性 * pom文件内 * maven依赖管理 * maven会自动包含可传递的依赖项,避免了需要手动指定项目依赖项所需要依赖的库。 * 所有从父项目继承的依赖项,或者依赖项所需的依赖,都会在maven的项目中 * 依赖中介: * 当项目中存在一个依赖的多个版本时,会选择在依赖树中距离当前项目最近的依赖所选择的版本。如果两个不同版本的依赖项距离当前的项目深度相同,那么第一个被声明的依赖项版本获胜。 * 可以在项目中明确声明依赖项的版本来保证依赖项版本 * 依赖管理: * 可以在dependencyManagement中添加依赖,添加后当发生依赖版本冲突或者没有指定依赖版本时,会使用dependencyManagement中定义的依赖版本 * springboot在spring-boot-dependencies的pom文件中指定了一些依赖的默认版本,故而在构建springboot项目时一些依赖项并不用指定版本信息 * 在dependencyManagement中,子项目声明的依赖会优于父项目声明的依赖,如果父项目和子项目同时在依赖管理中声明一个依赖的不同版本,那么以子项目声明的为准 * 当发生版本冲突时,依赖管理优先于依赖中介,并不是看依赖距离当前项目的深度来决定版本,而是看依赖管理中定义的版本来决定 * dependency scope: * 该机制可以允许maven只包含适用于当前阶段的依赖 * dependency scope: * compile:默认的scope,在所有阶段的classpath中都可用 * provided:声明为provided表明其只在编译和测试的时候被需要,而在运行时环境中classpath中并不包含该依赖,该依赖会在runtime中被提供 * runtime:表明该依赖只在运行时环境中被需要,在runtime classpath中存在该依赖,但是并无法在compile时被访问 * test:该依赖只会在测试时被使用,而在正式情况下不需要该依赖 * system:类似于provided,但是必须要提供明确包含该依赖的jar包。该依赖必须一直可见并且不会再仓库中去查找。 * system依赖要通过配置systemPath来指定该依赖的路径 * import:仅用于dependencyManagement中的依赖,表示将当前依赖替换为目标pom文件中dependencyManagement中的内容 * 当导入的依赖版本于当前依赖管理中自定义的依赖版本冲突时,以自定义的依赖版本为准 * import通常用于解决只能继承一个父pom中依赖管理的问题,可以通过import来导入多个pom文件的依赖继承 * 当import多个pom文件中的依赖管理时,如果发生了冲突, * 如果自定义的依赖管理项中包含冲突依赖,以自定义的版本为准 * 如果自定义的依赖管理项中不包含冲突依赖,那么以最先被导入的版本为准 * exclude依赖: * 可以在依赖中指定exclusion来排除某依赖 * 使用场景: * 当项目的某个依赖项依赖了一个存在安全问题或者于jdk版本不兼容的依赖项,那么可以通过exclusion来排除该依赖项 * 当对一个依赖项中的某个依赖进行排除时,不仅可以排除依赖项的直接依赖项,还可以排除该依赖项的传递依赖项 * 可选依赖 * 可以通过为依赖添加optional标签来将依赖声明为可选的 * 如果依赖被声明为可选的,如项目B声明依赖A时可选的,那么当C依赖项目B时,C将不会包含依赖A,如果C要包含依赖A,需要显式的声明依赖A * 可选依赖的使用场景: * 如果库X2提供多种数据库的访问API,故而X2需要各种数据库的driver依赖,但是如果项目C依赖了X2,那么项目C仅需要一种数据库的driver。此时X2可以将各种driver声明为可选的,当项目C依赖X2时,仅需显式依赖于其选择的一种driver依赖即可