Maven pom.xml 详解

一、pom 简介

POM 是项目对象模型 (Project Object Model) 的简称, XML 格式,名称为 pom.xml ,它是 Maven 项目的核心配置文件,该文件用于管理源代码、配置文件、开发者的信息和角色、问题追踪系统、组织信息、项目授权、项目的url、项目的依赖关系等等.事实上,在 Maven 的世界中,一个项目可以什么都没有,甚至没有代码,但是必须包含 pom.xml 文件.并且一个 Maven 项目有且只有一个 pom.xml 文件,该文件必须在项目的根目录下.

 
二、pom.xml 完整结构
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
            http://maven.apache.org/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、全局变量 properties

properties: 全局属性,一般情况下用于定义全局的 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、dependency

dependency 标签统一的定义在 dependencies 标签中,它代表的意思是我们可以通过该标签引入我们需要的相关 jar 包

3.1、如何查找一个 jar 包的地址?

Maven 依赖官网:https://mvnrepository.com/

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­fileupload

例如:我们修改 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 目录下使用这个依赖),不参与打包部署.典型的例如: junit

4.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 包

引入 Oracle 驱动之后就可以使用了,没有出现报错

其实吧,我觉得如果某些 jar 包 Maven 中央仓库没有录入,我们可以将需要的 jar 包下载下来,然后上传到私服中,通过左边从私服中下载就可以了.

这里总结一下 scope 依赖范围

  对主程序是否有效 对测试程序是否有效 是否参与打包 是否参与部署 典型例子
compile spring-context
test junit
provided servlet-api、jsp-api
runtime mysql-connector-java
system - - - - -

4.6、远程仓库 repositories

repositories:用来配置当前工程使用的远程仓库

依赖查找顺序:本地仓库--->当前工程 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>http://maven.aliyun.com/nexus/content/groups/public/</url>
	</repository>
</repositories>

 

4.7、插件 plugins

插件,就是一种工具.常见的如:清理插件 maven­clean­plugin ,编译插件 maven­compile­plugin

插件和依赖的区别:插件是工具,偏向于开发环境.和项目功能、源码、打包好的 jar 包没有任何关系.插件和依赖的关系,类似于 IDEA 工具和上线的 jar 包.

Maven 的核心文件很小,主要的任务都是由插件来完成.定位到:%本地仓库%orgapachemavenplugins ,可以看到一些下载好的插件

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 的安装目录inmaven-model-builder-3.6.0.jarorgapachemavenmodelpom-4.0.0.xml

解压开 maven-model-builder-3.6.0.jar 这个压缩包,里面有两个目录

在 org/apache/maven/model/ 目录下有一个 pom-4.0.0.xml ,这个 pom 就是超级 pom ,例如里面就配置了相关的仓库信息

 
原文地址:https://www.cnblogs.com/xiaomaomao/p/14152228.html