一、概述
Maven是 Apache 下的一个纯 Java 开发的开源项目。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。
Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。
Maven 也可被用于构建和管理各种项目,例如 C#,Ruby,Scala 和其他语言编写的项目。Maven 曾是 Jakarta 项目的子项目,现为由 Apache 软件基金会主持的独立 Apache 项目。
1、Maven功能
Maven 能够帮助开发者完成以下工作:
- 构建
- 文档生成
- 报告
- 依赖
- SCMs
- 发布
- 分发
- 邮件列表
2、约定配置
Maven 提倡使用一个共同的标准目录结构,Maven 使用约定优于配置的原则,大家尽可能的遵守这样的目录结构。如下所示:
目录 | 目的 |
---|---|
${basedir} | 存放pom.xml和所有的子目录 |
${basedir}/src/main/java | 项目的java源代码 |
${basedir}/src/main/resources. | 项目的资源,比如说property文件,springmvc.xml. |
${basedir}/src/test/java | 项目的测试类,比如说Junit代码 |
${basedir}/src/test/resources | 测试用的资源 |
${basedir}/src/main/webapp/WEB-INF | web应用文件目录,web项目的信息,比如存放web.xml、本地图片、jsp视图页面 |
${basedir}/target | 打包输出目录 |
${basedir}/target/classes | 编译输出目录 |
${basedir}/target/test-classes | 测试编译输出目录 |
Test.java | Maven只会自动运行符合该命名规则的测试类 |
~/.m2/repository | Maven默认的本地仓库目录位置 |
3、Maven 特点
项目设置遵循统一的规则。
任意工程中共享。
依赖管理包括自动更新。
一个庞大且不断增长的库。
可扩展,能够轻松编写 Java 或脚本语言的插件。
只需很少或不需要额外配置即可即时访问新功能。
基于模型的构建 − Maven能够将任意数量的项目构建到预定义的输出类型中,如 JAR,WAR 或基于项目元数据的分发,而不需要在大多数情况下执行任何脚本。
项目信息的一致性站点 − 使用与构建过程相同的元数据,Maven 能够生成一个网站或PDF,包括您要添加的任何文档,并添加到关于项目开发状态的标准报告中。
发布管理和发布单独的输出 − Maven 将不需要额外的配置,就可以与源代码管理系统(如 Subversion 或 Git)集成,并可以基于某个标签管理项目的发布。它也可以将其发布到分发位置供其他项目使用。Maven 能够发布单独的输出,如 JAR,包含其他依赖和文档的归档,或者作为源代码发布。
向后兼容性 − 您可以很轻松的从旧版本 Maven 的多个模块移植到 Maven 3 中。
子项目使用父项目依赖时,正常情况子项目应该继承父项目依赖,无需使用版本号,
并行构建 − 编译的速度能普遍提高20 - 50 %。
更好的错误报告 − Maven 改进了错误报告,它为您提供了 Maven wiki 页面的链接,您可以点击链接查看错误的完整描述。
二、POM详解
POM(Project Object Model, 项目对象模型)是Maven工程的基本工作单元,是一个XML文件, 包含了项目的基本信息, 用于描述项目如何构建、声明项目依赖等。执行任务或目标时, Maven会从项目中寻找POM。它读取POM,获取所需的配置信息,然后执行目标。
POM中可以指定以下配置:
- 项目依赖
- 插件
- 执行目标
- 项目构建Profile
- 版本信息
- 项目开发者列表
- 相关邮件列表等信息
等等。
2.1、POM文件格式
POM文件的格式由Maven的XSD文件定义, 如[maven-4.0.0.xsd](http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd):
good-java
org.example
1.0-SNAPSHOT
4.0.0
org.example
good-java-spring
jar
1.0-SNAPSHOT
good-java-spring
http://www.baidu.com/dipper
项目描述信息
8
jira
http://jira.baidu.com/dipper
ci
http://127.0.0.1:8080/
mail
true
true
false
false
test
2021
Demo
[email protected]
[email protected]
[email protected]
http:/hi.baidu.com/test/demo/dev/
dipper
skyeye
[email protected]
Project Manager
Architect
demo
http://hi.baidu.com/dipper
No
-5
none
[email protected]
http://www.baidu.com/none
none
Apache 2
http://www.baidu.com/dipper/LICENSE-2.0.txt
repo
A business-friendly OSS license
scm:svn:http://svn.baidu.com/dipper/maven/dipper/dipper-maven2-trunk(dao-trunk)
scm:svn:http://svn.baidu.com/dipper/maven/dipper/dao-trunk
http://svn.baidu.com/dipper
demo
http://www.baidu.com/dipper
prod
true
Windows XP
Windows
x86
5.1.2600
mavenVersion
2.0.3
/usr/local/test
/usr/local/test
/src/main/java
/src/main/java
/src/test/java
/target
/target/test
org.example
good-java-annotation
1.0-SNAPSHOT
test-compile
config
true
/profile/${profile.id}
*
*.bak
/target
${artifactId}
/profile/${profile.id}
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
true
default
compile
true
test
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
true
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
true
default
compile
true
test
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
true
../good-java-example
true
always
warn
default
default
http://192.168.1.169:9999/repository/
default
org.apache.maven
maven-artifact
3.8.1
jar
test
spring-core
org.springframework
true
true
/site
org.apache.maven.plugins
maven-compiler-plugin
3.8.1
true
default
true
1
true
maven2
maven2
file://${basedir}/target/deploy
default
true
maven2
maven2 Snapshot Repository
scp://svn.baidu.com/dipper:/usr/local/maven-snapshot
default
dipper-site
business api website
scp://svn.baidu.com/dipper:/var/www/localhost/dipper-web
none
2.2、POM 重要标签简介
-
project.parent
: 父项目的坐标。 -
project.groupId
: 项目的全球唯一标识符。 -
project.artifactId
: 项目的标识符, 它和groupId一起唯一标识一个项目 -
project.version
: 项目的版本号, 它和groupId、artifactId一起构成项目的三元组, 代表项目唯一的一个版本。 -
project.packaging
: 项目的构建类型, 默认包括jar、war、ear、pom等, 但不是全部, 通过其他插件还可以构建其他的构建类型, 比如tar等等。
-project.properties
: 可以自定义元素, 在其他的元素中进行应用, 本质上是一个声明变量的地方, 比如jdk版本号之类的。 -
project.profiles
: 针对项目不同运行环境声明不同的构建方式, 如果被激活, 会修改项目的构建方式。比如开发时一般会区分为dev、test、prod等环境,不同的环境之间默认一般会隔离,所以它的资源的加载方式都不一样, 就需要用profile分别定义, 用到哪个环境, 就激活哪个环境。它主要会影响project
中默认定义的build
、repositories
、pluginRepositories
、dependencyManagement
、distributionManagement
、dependencies
等元素。 -
project.build
: 构建项目需要的信息, 主要包含构建项目的源文件路径、目标目录、资源文件目录、构建扩展、资源文件包含列表、插件列表、构建目标等等。 -
project.modules
: 模块或子项目, 时构建的一部分。 -
project.repositories
: 发现依赖的远程仓库列表。 -
project.pluginRepositories
: 发现插件的远程仓库列表。 -
project.dependencies
: 描述项目构建的所有依赖情况。 -
project.dependencyManagement
: 继承自该项目的子项目的默认依赖信息, 如果子项目声明一个依赖某些信息未描述, 就会使用这里的依赖信息。 -
project.distributionManagement
: 项目分发信息, 表示项目构建完成后发布的仓库位置。
2.3、POM 重要标签详解
1. dependency标签
dependency
标签标识了项目依赖的某个组件的信息, 包含被依赖组件的唯一标识三元组groupId
、artifactId
、version
。
type
表示依赖的类型, 可选值和project.packaging
类似, 默认是jar
, 可以通过设置extensions
构建新的类型。
scope
表示依赖的范围, 主要包含:
test
表示应用程序的正常使用不需要依赖,只在测试编译和执行阶段可用。此作用域不可传递。通常,此范围用于测试库,例如 JUnit 和 Mockito。runtime
表示被依赖项目无需参与项目的编译,但是会参与到项目的测试和运行。与compile相比,被依赖项目无需参与项目的编译。
例如,在编译的时候我们不需要 JDBC API 的 jar 包,而在运行的时候我们才需要 JDBC 驱动包。compile
compile 是默认值,如果没有指定 scope 值,该元素的默认值为 compile。被依赖项目需要参与到当前项目的编译,测试,打包,运行等阶段。打包的时候通常会包含被依赖项目。system
system 元素与 provided 元素类似,但是被依赖项不会从 maven 仓库中查找,而是从本地系统中获取,systemPath
元素用于制定本地系统中 jar 文件的路径。provided
被依赖项目理论上可以参与编译、测试、运行等阶段,相当于compile,但是在打包阶段做了exclude的动作。
例如, 如果我们在开发一个web 应用,在编译时我们需要依赖 servlet-api.jar,但是在运行时我们不需要该 jar 包,因为这个 jar 包已由应用服务器提供,此时我们需要使用 provided 进行范围修饰。import
: 该作用域只在dependencyManagement
元素中生效, 可以代替parent继承。parent继承的方式存在的问题在于, 如果子module特别多, 需要将子module的依赖都在parent中声明, 这样子会造成parent中dependencyManagement
特别庞大, 无法进行有效的分类。 这个时候采用import scope的方式就可以有效解决, 可以声明多个不同类型的pom, 在子mudule的dependencyManagement
中按需引入即可。 import scope代替parent继承的方式:
org.exmaple
parent
1.0.0
pom
com.test
test1
1.0.0
org.junit
junit
0.0.1
test
这样就可以在子module中引入了:
org.exmaple
mudule1
1.0.0
jar
org.example
parent
1.0.0
pom
import
com.test
test1
org.junit
junit
exclusions
表示要排除的依赖。
systemPath
只有在以来范围是system
的时候才生效,表示依赖在本地文件系统的位置。
optional
表示可选依赖, 默认值为false, 依赖具备传递性,比如A->B->C, 按照默认值, A也会依赖C, 如果B依赖C时声明了optional
为true, 则A不会依赖C。如下:
// B项目POM声明:
org.example
C
1.0.0
true
classifier
表示依赖的分类器,classifier元素用来帮助定义构件输出的一些附属构件。附属构件与主构件对应,比如主构件是 kimi-app-2.0.0.jar 该项目可能还会通过使用一些插件生成 如 kimi-app-2.0.0-javadoc.jar 、 kimi-app-2.0.0-sources.jar 这样两个附属构件。这时候,javadoc,sources就是这两个附属构件的classifier,这样附属构件也就拥有了自己唯一的坐标。
maven中一般使用groupId
、artifactId
、version
来唯一标识一个组件, 但是有一些特殊的组件,具备更细粒度, 需要增加classifier
来声明依赖, 否则会报错找不到jar包, 比如 JSON-lib:
这个时候就必须使用classifier属性指定了:
net.sf.json-lib
json-lib
2.4
jdk15
2. build标签
finalName
表示构建目标文件的名称, 默认在${basedir}/target目录下, 一般使用project.artifactId
。
directory
表示构建目标文件的存放目录,默认是${basedir}/target。
sourceDirectory
表示项目源代码的目录, 默认是${basedir}/src/main/java。
scriptSourceDirectory
表示项目脚本的源代码的目录。大多数情况下构建时会被拷贝到目标目录下。
outputDirectory
表示构建目标中class文件的存放目录, 默认是${basedir}/target/classes。
testSourceDirectory
表示项目测试源代码的目录, 默认是${basedir}/src/test/java。
testOutputDirectory
表示构建目标中测试class文件的存放目录, 默认是${basedir}/target/test-classes。
resources
表示项目中资源文件的位置, 用于包含或排除某些资源文件。
resource
: 一个与项目关联的资源文件的列表, 用来描述资源文件是什么和在哪里。targetPath
: 表示构建完后resource文件存放的位置,默认是basedir, 通常打包在jar包中的资源文件的目标目录是META-INF。directory
: 表示resource文件所在的目录, 通常是${basedir}/src/main/resources。filtering
: true/false, 表示构建时是否用元素和 元素中列出的属性文件中定义的值替换掉资源文件中的同名的属性。 比如:
Tom
true
/src/main/resources
假如/src/main/resources下有一个application.properties, 其中有一行:
username: ${username}
编译完成后, 就会变成:
username: Tom
includes
: 表示包含哪些资源文件, 以*作为通配符。excludes
: 表示忽略哪些资源文件。
testResources
: 表示项目中测试资源文件的位置, 用法和resources
一致。
defaultGoal
: 表示构建时执行的阶段, 默认是install, 即如果在命令行中执行mvn, 相当于执行mvn install。
filters
: 定义.properties文件,包含一个properties列表,该列表会应用到支持filter的resources中。也就是说,定义在filter的文件中的name=value键值对,会在build时代替${name}值应用到resources中。* 它可以配合profile
标签进行不同环境的隔离配置。
/profiles/${profile.id}/*.properties
plugins
: 表示构建的插件。
groupId
: 代表插件的全球唯一ID, 默认org.apache.maven.plugins
artifactId
: 代表插件的IDversion
: 代表插件的版本号。-
executions
: 配置包含一组指示插件如何执行的属性:id : 执行器命名
phase:标识执行的阶段
goals:标识执行的目标或功能
configuration:标识执行目标所需的配置文件 extensions
: 标示是否扩展goals
: 标示执行的阶段inherited
: 标示是否继承dependencies
: 插件的依赖configuration
: 插件的自定义配置信息
extensions
: 表示构建需要用到的一系列扩展, 具体目前不知道怎么用, TODO。
pluginManagement
: 表示构建时插件的声明。 它与plugins
区别与dependencies
和dependencyManagement
的区别一致。
3. profiles标签
profiles
标签表示不同环境的maven配置, 比如仓库配置、依赖配置、插件配置、构建配置, 基本上覆盖了maven配置的重要几个方面。在开发过程中, 我们的项目往往会存在多个环境, 比如:开发环境、测试环境、预发环境、线上环境等, 往往不同环境数据源配置、日志配置等等不一样, 这样我们每次部署到不同的环境, 都需要修改配置进行构建打包, 来回修改很容易出错,并且浪费时间人力。
profiles
标签就是为了解决以上问题而存在的, 可以看到profiles
标签的定义如下:
prod
true
id
: 表示不同环境的Profile的唯一ID。
activation
: 表示Profile激活的方式, 可以根据jdk版本、操作系统版本、maven属性、文件存在或缺失等方式来激活。它的定义如下:
true
1.7
-
activeByDefault
: 表示默认激活 -
jdk
: 表示根据jdk版本激活。 -
os
: 表示根据操作系统激活 -
property
: 表示根据maven属性激活。 -
file
: 表示根据文件存在不存在激活。
properties
: 表示Profile自定义的属性, 可以定义通过, 通常用来其他地方引用, 比如表示环境变量等。
其他字段和POM文件中一级标签一致, 详见各个标签的使用方式。
激活方式:
- 根据环境自动激活, 如上所示根据jdk、os等激活。
- 通过命令行参数激活, 如:mvn command -Pprofile, 就会激活对应profile。
- 配置默认自动激活, 通过activeByDefault来设置。
使用方式:
比如,我们有2个环境:开发环境(dev)和线上环境(prod), 它的配置如下:
dev
true
dev
prod
prod
/profiles/${env}/*.properties
/src/main/resources
true
这样子当我们选择不同的环境时, filters就会根据不同的环境加载不同的配置文件并且应用到资源文件中,替换同名的键值对, 比如替换jdbc的配置等等。
除过使用不同的配置, Profile
还可以帮助在不同环境使用不同的maven仓库、发布仓库, 采用不同的构建过程,构建不同的包等等。
4. dependencyManagement标签
denpendencyManagement
用来统一管理项目的依赖版本号, 确保各个子项目的依赖和版本一致,不用每个项目都单独声明依赖的版本号。当变更版本号时,只需要在父项目的denpendencyManagement
中修改版本号, 子项目不需要任何修改; 如果子项目依赖于一个特殊的版本号, 只需要在自己的dependencies
中修改即可。
-
dependencies
: 描述项目的依赖信息, 见dependencies
标签。
它与dependencies
的区别:
denpendencies
相对于dependencyManagement
, 所有子项目dependencies
声明的依赖如果没有单独声明版本号, 就会使用dependencyManagement
中声明的版本号。dependencyManagement
只是声明依赖的版本号, 并不实际引入依赖, 因此子项目需要实际引入依赖。 dependencyManagement里只是声明依赖,并不自动实现引入,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。