Mavenpom.xml详解⼀、pom 简介POM 是项⽬对象模型 (Project Object Model) 的简称, XML 格式,名称为 pom.xml ,它是 Maven 项⽬的核⼼配置⽂件,该⽂件⽤于管理源代码、配置⽂件、开发者的信息和⾓⾊、问题追踪系统、组织信息、项⽬授权、项⽬的url、项⽬的依赖关系等等.事实上,在 Maven 的世界中,⼀个项⽬可以什么都没有,甚⾄没有代码,但是必须包含 pom.xml ⽂件.并且⼀个 Maven 项⽬有且只有⼀个 pom.xml ⽂件,该⽂件必须在项⽬的根⽬录下.⼆、pom.xml 完整结构<project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 基本设置 The Basics --><groupId>...</groupId><artifactId>...</artifactId><version>...</version><packaging>...</packaging><dependencies>...</dependencies><parent>...</parent><dependencyManagement>...</dependencyManagement><modules>...</modules><properties>...</properties><!-- 构建过程的设置 Build Settings --><build>...</build><reporting>...</reporting><!-- 项⽬信息设置 More Project Information --><name>...</name><description>...</description><url>...</url><inceptionYear>...</inceptionYear><licenses>...</licenses><organization>...</organization><developers>...</developers><contributors>...</contributors><!-- 环境设置 Environment Settings --><issueManagement>...</issueManagement><ciManagement>...</ciManagement><mailingLists>...</mailingLists><scm>...</scm><prerequisites>...</prerequisites><repositories>...</repositories><pluginRepositories>...</pluginRepositories><distributionManagement>...</distributionManagement><profiles>...</profiles></project>我们这⾥就选择⼀些⽐较常⽤的配置来说三、pom 常⽤配置1、坐标坐标是⼀个项⽬的唯⼀标识符,可以通过坐标准确的定位到某⼀个具体的项⽬.有了坐标进⾏定位之后,如果其它的 Maven 项⽬想使⽤该项⽬⽣成的 jar 包,只需要通过坐标引⼊依赖即可Maven 坐标是通过 groupId、artifactId、version 来共同定位的.groupId: 组织 Id ,表⽰当前模块所⾪属的项⽬.起名规范:⼀级域名(com、org).⼆级域名(公司名称).项⽬名称artifactId: 模块 Id, 表⽰⼀个项⽬中的某个模块,例如商城项⽬⾥⾯的订单模块、⽤户模块、商品模块...等等version:当前的版本为什么坐标需要三个元素才能定位呢?⽐如你⾃⼰的项⽬中需要使⽤某⼀个 jar 包,那么怎么找到这个 jar 包呢?这个时候你就需要使⽤ groupId 来定位这个 jar 包是属于哪个公司的哪个项⽬,定位到了项⽬之后呢,你还需要使⽤ artifactId 定位到该项⽬的具体模块,因为⼀个项⽬可以有很多的模块,定位到了具体模块之后呢,还需要使⽤ version 来定位具体的版本号,因为⼀个模块可以进⾏迭代,如果不指定具体的版本号也就⽆法准确的定位,这个类似于地理⾥⾯只有通过东经和北纬才能准确定位⼀个地理位置⼀样.<!-- 组织 Id --><groupId>com.xiaomaomao.springAnalyse</groupId><!-- 模块 Id --><artifactId>spring-ioc</artifactId><!-- 具体的版本号 --><version>1.0-SNAPSHOT</version>2、全局变量 propertiesproperties: 全局属性,⼀般情况下⽤于定义全局的 jar 包版本.仅仅是定义全局变量,不起其他作⽤.应⽤场景:在实际项⽬中如果我们使⽤同⼀个公司的 jar 包, jar 包的版本号最好是保持⼀致,因为有时候 jar 包版本不⼀致的情况下,有可能会出现不同版本之间发⽣不兼容的错误, 我们这⾥就以 spring 为例,下⾯的这些依赖当中 spring-context、spring-webmvc 都是属于 spring 的 jar 包,并且它们的版本号都是 4.3.11.RELEASE,突然有⼀天,项⽬经理兴奋的告诉我,spring 推出了 5.0 版本,功能很强⼤,我们要升级版本,那么这个时候你就只能挨个的找到 spring 相关的依赖,⼀个⼀个的把它们升级到 5.0 版本,我们这⾥仅仅只有两个 spring 相关的依赖,改起来⽐较快,可是如果你的项⽬⾥⾯使⽤了⼏⼗个,甚⾄上百个 spring 的依赖呢?这个时候你挨个挨个的去替换,⼯作量⽐较⼤,并且还有可能⼀不留神改错了,好不容易改完了,也没有改错,终于可以休息⼀下了,这个时候项⽬经理那个糟⽼头⼦⼜来了,他告诉你 spring 5.0 有版本缺陷,我们还是改回原来的 4.3.11.RELEASE 版本吧,我想此时你是奔溃的,你就只能挨个挨个的将 spring 的依赖 jar 包⼀个⼀个的还原,好了,还原了,也改好了,终于没事了,你冷不丁的冒出⼀个念头,万⼀项⽬经理⼜要我切换成其它的版本,⼯作量太⼤了,有没有什么⽐较好的办法呢?答案是有的,我们就可以通过 properties 标签来统⼀管理 jar 包的版本<dependencies><!-- spring 基本依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.11.RELEASE</version></dependency><!-- spring-webmvc 依赖 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.3.11.RELEASE</version></dependency><!-- juint 依赖 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- servlet-api 依赖 --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.0</version><scope>provided</scope></dependency></dependencies>在 <properties> 标签中定义⼀类 jar 包的版本,引⼊依赖的时候通过 ${标签名} 的⽅式来控制版本<properties><!--标签名称任意,但是最好是⼀个有意义的名称--><spring-version>4.3.11.RELEASE</spring-version><junit-version>4.11</junit-version><javax.servlet-version>4.0.0</javax.servlet-version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><!--使⽤ ${⾃定义的标签} 来引⼊ properties 中定义的标签⾥⾯的值--><version>${spring-version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring-version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit-version}</version><scope>test</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>${javax.servlet-version}</version><scope>provided</scope></dependency></dependencies>如果以后想统⼀切换 spring、junit 等 jar 包的版本,我们只需要在 properties 标签中切换就可以了,再也不⽤去依赖中挨个挨个的替换 jar 包的版本了3、dependencydependency 标签统⼀的定义在 dependencies 标签中,它代表的意思是我们可以通过该标签引⼊我们需要的相关 jar 包3.1、如何查找⼀个 jar 包的地址?Maven 依赖官⽹:3.1.1、进⼊官⽹,查找需要的 jar 包3.1.2、选择 jar 包版本3.1.3、复制依赖到项⽬ pom.xml 中3.2、如何查看引⼊的依赖4、依赖的 scope 作⽤域依赖的 scope 标签表⽰的意思是依赖的使⽤范围(也就是这个 jar 包在什么范围内是可以使⽤的),scope 的取值有 compile、test、provided、runtime、system 4.1、compile该依赖可以在整个项⽬中使⽤(是指代码范围, main ⽬录和 test ⽬录下都能使⽤这个依赖),参与打包部署.是 scope 的默认值.典型的例如: commons f ileupload 例如:我们修改 spring 核⼼依赖 spring-context 的 scope 为 test<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring-version}</version><scope>test</scope></dependency>在 main ⽬录下使⽤就出现了报错在 test ⽬录下使⽤就是正常的4.2、test该依赖只能在测试代码中使⽤(是指代码范围,只能在 test ⽬录下使⽤这个依赖),不参与打包部署.典型的例如: junit4.3、provided该依赖编写源代码时需要使⽤,因为当我们使⽤ Servlet 的时候,如果不添加 javax.servlet-api 依赖,就⽆法使⽤⾥⾯相关的 API,如果使⽤了编译就会报错,provided 不参与打包部署.只是在编写源码的时候使⽤,为什么不参与打包部署呢?因为我们的项⽬打包部署到服务器的时候,服务器会为我们提供 javax.servlet-api ,这⾥以 tomcat 为例,找到 tomcat 的安装⽬录,打开⾥⾯的 lib ⽬录,在 tomcat 容器启动的时候会为我们提供 servlet-api.jar ,那么我们项⽬中的 pom.xml 中就不需要再提供 servlet-api 这个依赖了4.4、runtime该依赖编写代码时不需要,运⾏时需要,参与打包部署.典型的例如数据库驱动 mysql-connector-java<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.20</version></dependency>为什么编写代码时不需要呢?jvm 运⾏期的时候通过反射加载数据库驱动,完成例如注册驱动、获取连接、获取 PrepareStatement 对象等,我们编写代码的时候只是在编译期间,根本不会使⽤到数据库驱动,项⽬最终打包部署的时候也是需要数据驱动的,否则你⽆法连接数据库和操作 Sql 语句.4.5、system表⽰使⽤本地系统路径下的 jar 包,需要和 systemPath 配合使⽤,典型的例如 Oracle 数据库驱动: ojdbc.jar ,它是未授权 Maven 中央仓库的(刚刚去 Maven 中央仓库发现有,但是我们就假设它没有被Maven 中央仓库录⼊)有些 jar 包可能因为授权的问题或者是⼀些个⼈的 jar 包,这些 jar 包不会被 Maven 中央仓库录⼊,这个时候如果我们想在项⽬中使⽤这些 jar 包的话,我们可以先将 jar 包下载先来,然后可以在 pom.xml 中配置指向本地某个 jar 包的路径,引⼊相关的 jar 包对主程序是否有效对测试程序是否有效是否参与打包是否参与部署典型例⼦compile 是是是是spring-context test 否是否否junit provided 是是否否servlet-api 、jsp-api runtime 否否是是mysql-connector-java system -----引⼊ Oracle 驱动之后就可以使⽤了,没有出现报错其实吧,我觉得如果某些 jar 包 Maven 中央仓库没有录⼊,我们可以将需要的 jar 包下载下来,然后上传到私服中,通过左边从私服中下载就可以了.这⾥总结⼀下 scope 依赖范围4.6、远程仓库 repositoriesrepositories:⽤来配置当前⼯程使⽤的远程仓库依赖查找顺序:本地仓库--->当前⼯程 pom.xml 中配置的远程仓库--->⽤户级别的 settings.xml 中配置的远程仓库----> 全局 settings.xml 中配置的远程仓库---->Maven 中央仓库应⽤场景:如果有些 jar 包在 Maven 中央仓库没有,但是在其他仓库(例如:阿⾥仓库、spring 仓库、mybatis 仓库)⾥是有这个 jar 包的,例如 spring 新发布了⼀个版本,由于是刚发⾏的版本,性能不太稳定,这个时候Maven 中央仓库⼀般不会将这些 jar 包录⼊,但是你就是想⽤ spring 最新的版本,那么可以在 pom.xml 中通过配置 repositories 从指定的某公司官⽅仓库来获取相应的 jar 包<repositories><!-- 配置 spring 官⽅仓库 --><repository><!-- 远程仓库唯⼀标识符 --><id>spring_repo</id><!-- 仓库名称,可以使⽤⼀个有意义的名称命名 --><name>Private Repository</name><!-- spring 官⽅远程仓库地址 --><url>http://repo.spring.io/milestone</url><!-- ⽤于定位和排序构件的仓库布局类型,它的取值有 default(默认)或 legacy(遗留) --><layout>default</layout><releases><!-- 是否开启 release 或者 snapshots 的下载⽀持.默认值为 false ,表⽰不会从该中央仓库下载快照版本的构件 --><enabled>true</enabled><!-- ⽤来配置 Maven 从远程仓库检查更新的频率,默认是 daily,表⽰每天检查⼀次;never: 从不检查更新;always: 每次构建都检查更新;interval:X 每隔 X 分钟检查⼀次更新 --><updatePolicy>always</updatePolicy><!--⽤来配置 Maven 检查检验和⽂件的策略,当构建被部署到Maven 仓库中时,会同时部署对于应⽤的检验和⽂件,在下载构件的时候, Maven 会验证校验和⽂件checksumPolicy 默认值是 warn ,会执⾏构建时输出警告信息fail :遇到校验和错误就构件失败ignore :完全忽略校验和错误 --><checksumPolicy>warn</checksumPolicy></releases><snapshots><enabled>true</enabled><updatePolicy>always</updatePolicy></snapshots></repository><!-- 配置 阿⾥ 官⽅远程仓库 --><repository><id>alimaven</id><name>aliyun maven</name><url>/nexus/content/groups/public/</url></repository></repositories>4.7、插件 plugins插件,就是⼀种⼯具.常见的如:清理插件 maven c lean p lugin ,编译插件 maven c ompile p lugin插件和依赖的区别:插件是⼯具,偏向于开发环境.和项⽬功能、源码、打包好的 jar 包没有任何关系.插件和依赖的关系,类似于 IDEA ⼯具和上线的 jar 包.Maven 的核⼼⽂件很⼩,主要的任务都是由插件来完成.定位到:%本地仓库%\org\apache\maven\plugins ,可以看到⼀些下载好的插件4.7.1、插件的⽬标 (Plugin Goals)⼀个插件通常可以完成多个任务,每⼀个任务就叫做插件的⼀个⽬标.如执⾏ mvn install 命令时,调⽤的插件和执⾏的插件⽬标如下4.7.2、将插件绑定到⽣命周期Maven 的⽣命周期是抽象的,实际需要插件来完成任务,这⼀过程是通过将插件的⽬标 (goal) 绑定到⽣命周期的具体阶段 (phase) 来完成的.例如将 maven-compiler-plugin 插件的 compile ⽬标绑定到 default ⽣命周期的 compile 阶段,完成项⽬的源代码编译.Maven 对⼀些⽣命周期的阶段(phase)默认绑定了插件⽬标,因为不同的项⽬有 jar、war、pom 等不同的打包⽅式,因此对应的有不同的绑定关系,其中针对 default ⽣命周期的 jar 包打包⽅式的绑定关系如下第⼆列中,冒号后⾯即是绑定的插件⽬标,冒号前⾯是插件的前缀(prefix),是配置和使⽤插件的⼀种简化⽅式.4.7.3、⾃定义绑定⽤户可以根据需要将任何插件⽬标绑定到任何⽣命周期的阶段, 例如将 maven-source-plugin 的 jar-no-fork ⽬标绑定到 default ⽣命周期的 package 阶段, 这样,以后在执⾏ mvn package 命令打包项⽬时,在 package 阶段之后会执⾏源代码打包,⽣成如 ehcache-core-2.5.0-sources.jar 形式的源码包.<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId><version>2.2.1</version><executions><execution><id>attach-source</id><!-- 要绑定到的⽣命周期的阶段 --><phase>package</phase><goals><!-- 要绑定的插件的⽬标 --><goal>jar-no-fork</goal></goals></execution></executions></plugin></plugins>……</build>4.7.4、pom.xml 中配置插件<build><plugins><plugin><!-- 在这⾥添加 clean 插件,可以替换掉之前插件的版本 --><groupId>org.apache.maven.plugins</groupId><artifactId>maven-clean-plugin</artifactId><version>3.0.0</version></plugin><plugin><!-- ⼀般 web 项⽬需要添加⼀个 tomcat 插件 --><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><!-- 这⾥还可以配置 tomcat 的项⽬访问 URL 和项⽬访问端⼝ --><configuration><path>/xiaomaomao</path><port>8888</port></configuration></plugin></plugins></build>这⾥有个很奇怪的现象,我使⽤ IDEA 帮我创建 Web 项⽬, IDEA ⾃动帮我下载了插件,其中 maven-clean-plugin 插件的版本是 3.1.0 ,我这⾥把插件的版本替换成了 3.0.0然后看⼀下我们加⼊的 maven-tomcat 插件五、超级 pom当我们利⽤ IDEA 为我们创建⼯程的时候,我们没有进⾏任何配置,为什么能下载各种插件呢?这是由于存在超级 pom 的原因,所有的 Maven 项⽬都要继承超级 pom,⾥⾯有 Maven 默认的⼀些配置超级 pom 存放位置: Maven 的安装⽬录\bin\maven-model-builder-3.6.0.jar\org\apache\maven\model\pom-4.0.0.xml解压开 maven-model-builder-3.6.0.jar 这个压缩包,⾥⾯有两个⽬录在 org/apache/maven/model/ ⽬录下有⼀个 pom-4.0.0.xml ,这个 pom 就是超级 pom ,例如⾥⾯就配置了相关的仓库信息。