maven的这些东西你都懂吗?
Maven[ˈmevən]能帮你构建工程,管理jar包,编译代码,还能帮你自动运行单元测试,打包,生成报表,甚至能帮你部署项目,生成Web站点, 为开发者提供了一套完整的构建生命周期框架。开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置,因为 Maven 使用了一个标准的目录结构和一个默认的构建生命周期。
1. POM文件
Maven 工程结构和内容被定义在一个 xml 文件中 pom.xml
,是 Project Object Model (POM) 的简称,此文件是整个 Maven 系统的基础组件。POM 它放在工程根目录下,包含了关于工程和各种配置细节的信息,Maven 使用这些信息构建工程。也包含了目标和插件。当执行一个任务或者目标时,Maven 会查找当前目录下的 POM,从其中读取所需要的配置信息,然后执行目标。下面是一个简单的pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<groupId>Hust</groupId>
<artifactId>Gongmei</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Gongmei Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<lucene.version>6.0.1</lucene.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!--<scope>provided</scope>-->
</dependency>
</dependencies>
<build>
<!--解决IDEA自动重置LanguageLevel和JavaCompiler版本的问题-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<finalName>cloud</finalName>
</build>
</project>
POM文件的要求
- 每个工程应该只有一个 POM 文件。
- 所有的 POM 文件需要 project 元素和三个必须的字段:groupId, artifactId,version。表达当前工程的信息
- 在仓库中的工程标识为 groupId:artifactId:version
节点 | 说明 |
---|---|
groupID | 这是工程组的标识。它在一个组织或者项目中通常是唯一的。例如,一个银行组织 com.company.bank 拥有所有的和银行相关的项目。 |
artifactId | 这是工程的标识。它通常是工程的名称。例如,消费者银行。groupId 和 artifactId 一起定义了 artifact 在仓库中的位置。 |
version | 这是工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。例如:com.company.bank:consumer-banking:1.0 com.company.bank:consumer-banking:1.1. |
properties | 项目中的配置文件。指明项目中一些配置,例如字体编码以及版本号等 |
dependencies | 项目中的依赖文件。即项目中需要引入的jar包。 |
plugins | maven插件。Maven 实际上是一个依赖插件执行的框架,每个任务实际上是由插件完成。Build plugins:在构建时执行;Reporting plugins:在网站生成过程中执行 |
2. Maven构建声明周期
三个关键字:
- lifecycle 生命周期
- phase 阶段
- goal 目标
lifecycle 中包含phase ,phase 中包含goal 。
2.1 lifestyle
每个lifecycle 中都包含一个或多个phase 。通过 Maven 命令调用lifecycle中的phase时,该lifecycle中phase之前以及包括该phase在内的所有phase会被执行。Maven 有以下三个默认的生命周期:
- clean 删除构建目录
- build 构建应用
- site 创建新的报告文档、部署站点
2.2 phase
执行phase实际执行的是goal。如果一个phase没有绑定goal,这个phase就不会被执行。每个phase定义了一个或多个goals ,其中的goals是顺序执行。一些phase默认已经绑定了一些goal。对于default lifecycle来说, 这些被绑定的goal并不完全相同,而是和packaging value相关。
2.3 goal
最终被执行的就是goal,goal与goal之间是独立的。因此单独执行一个goal不会导致其他goal被执行。
e.g: mvn clean dependency:copy-dependencies package
,maven会顺序执行这3个对象中包含的所有goal。
3. Maven仓库
Maven仓库有三种类型:
- 本地(local)
- 中央(central)
- 远程(remote)
3.1 本地仓库
Maven 本地仓库保存你的工程的所有依赖(library jar、plugin jar 等)。当你运行一次 Maven 构建,Maven 会自动从中央库或远程库下载所有依赖的 jar 文件到本地仓库中。它避免了每次构建时都引用存放在远程机器上的依赖文件。
Maven 本地仓库默认被创建在 %USER_HOME% 目录下。要修改默认位置,在 %M2_HOME%\conf 目录中的 Maven 的 settings.xml 文件中定义另一个路径。
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>C:/MyLocalRepository</localRepository>
</settings>
3.2 中央仓库
Maven 中央仓库是由 Maven 社区提供的仓库,其中包含了大量常用的库。通俗一点说,就是一个网站,上面存放大量的库,项目中用到中央仓库的相关文件,就自动下载下来。可以在maven文件夹下的settings.xml中更改中央仓库的地址
<!-- mirror
| Specifies a repository mirror site to use instead of a given repository. The repository that
| this mirror serves has an ID that matches the mirrorOf element of this mi rror. IDs are used
| for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
|
<mirror>
<id>mirrorId</id>
<mirrorOf>repositoryId</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://my.repository.com/repo/path</url>
</mirror>
-->
3.3 远程仓库
如果 Maven 在中央仓库中也找不到依赖的库文件,它会停止构建过程并输出错误信息到控制台。可以在pom文件中指定远程仓库地址,那么Maven就会从该远程仓库下载依赖:
<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>
<groupId>com.companyname.projectgroup</groupId>
<artifactId>project</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>com.companyname.common-lib</groupId>
<artifactId>common-lib</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>companyname.lib1</id>
<url>http://download.companyname.org/maven2/lib1</url>
</repository>
<repository>
<id>companyname.lib2</id>
<url>http://download.companyname.org/maven2/lib2</url>
</repository>
</repositories>
</project>
3.4 Maven依赖搜索顺序
步骤 1 - 在本地仓库中搜索,如果找不到,执行步骤 2,如果找到了则执行其他操作。
步骤 2 - 在中央仓库中搜索,如果找不到,并且有一个或多个远程仓库已经设置,则执行步骤 4,如果找到了则下载到本地仓库中。
步骤 3 - 如果远程仓库没有被设置,Maven 将简单的停滞处理并抛出错误(无法找到依赖的文件)。
步骤 4 - 在一个或多个远程仓库中搜索依赖的文件,如果找到则下载到本地仓库已被将来引用,否则 Maven 将停止处理并抛出错误(无法找到依赖的文件)
4. Maven插件
另外一种将goal绑定到phase的方法就是在project中使用plugin,一个plugin可能有一个或多个goal,其中每个goal代表一个plugin的功能。
4.1 插件的使用
一、插件通常提供了一个目标的集合,可以使用下面的方法使用:
mvn [plugin-name]:[goal-name]
例如,一个 Java 工程可以使用 maven-compiler plugin 的 compile (goal) 编译,使用以下命令:
mvn compiler:compile
4.2 常用的插件列表
插件 | 说明 |
---|---|
clean | 构建之后清理目标文件(target文件),删除目标目录 |
compiler | 编译Java源文件 |
surefile | 运行junit单元测试,创建测试报告 |
jar | 从当前工程中构建jar文件 |
war | 从当前工程中构建war文件 |
javadoc | 为工程生成javadoc |
antrun | 从构建过程的任意一个阶段中运行一个ant任务的集合 |
5. Maven打包的详细过程
mvn clean package
执行详细过程如下:
mvn打包过程从图中我们可以看到Maven的执行顺序:
1、使用清理插件:maven-clean-plugin:2.5执行清理删除已有target目录(版本2.5)
2、使用资源插件:maven-resources-plugin:2.6执行资源文件的处理(版本2.6)
3、使用编译插件:maven-compiler-plugin:3.1编译所有源文件生成class文件至target\classes目录下(版本3.1)
4、使用资源插件:maven-resources-plugin:2.6:testResource执行测试资源文件的处理(版本2.6)
5、使用编译插件:maven-compiler-plugin:3.1:testCompile编译测试目录下的所有源代码(版本3.1)
6、使用插件:maven-surefire-plugin:2.12.4运行测试用例(版本2.12.4);
7、使用插件:maven-jar-plugin:2.4对编译后生成的文件进行打包,包名称默认为:artifactId-version,比如本例生成的jar文件:Gongmei-1.0-SNAPSHOT,包文件保存在target目录下,将该war包放入tomcat目录下的webapp中运行即可。
备注:不管是compile、package还是install等前三个步骤都是必不可少的,即清理已有目录,处理资源文件、编译源文件。
6. Maven常用插件
maven默认会依据项目类型自动把构建时的各阶段(Lifecycle和phase)自动绑定到特定插件提供的功能(goal)点上。例如java项目编译(compile)阶段,实际上是调用了maven-compiler-plugin插件提供的compile功能点来实现的。
- maven-resources-plugin 文件资源配置
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding> <!--配置资源文件编码-->
</configuration>
</plugin>
-
maven-compiler-plugin 编译配置
默认绑定到compile phase。maven2默认使用的是jdk5,jdk版本一般自己指定。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding> <!--指定utf-8版本-->
<compilerArgument>-Xlint:none</compilerArgument>
<compilerArguments>
<extdirs>libs</extdirs> <!--使用项目中的jar包-->
</compilerArguments>
</configuration>
</plugin>
-
maven-surefire-plugin 单元测试
默认绑定到test阶段
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore> <!--测试有失败用例时,是否继续构建-->
<skipTests>true</skipTests> <!--是否跳过测试阶段,方式1-->
<skip>true</skip> <!--是否跳过测试阶段,方式2-->
</configuration>
</plugin>
-
maven-jar-plugin 打jar包
普通java项目(非web项目或其它类型的特殊项目),package阶段默认绑定的插件,能够将编译好的class和资源达成jar包,但不包含依赖
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<excludes> <!--打包时要排除的文件-->
<exclude>agent.properties</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- <classpathPrefix>lib/</classpathPrefix> -->
<mainClass>com.demo.HelloWorld</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
-
maven-assembly-plugin 打包含依赖的全包
在打包时,对jar包的打包形式进行自定义配置
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<!--自定义配置文件-->
<descriptor>src/main/resources/package.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
下面是具体的配置package.xml
<assembly>
<id>bin</id>
<!-- 最终打包成一个用于发布的zip文件 -->
<formats>
<format>zip</format>
</formats>
- maven-war-plugin 打war包
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<warName>${project.artifactId}</warName>
<webResources>
<resource> <!--将额外的jar依赖打入war包-->
<directory>libs/</directory>
<targetPath>WEB-INF/lib</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</webResources>
<packagingExcludes>css/**,html/**</packagingExcludes>
</configuration>
</plugin>
- maven-source-plugin 打包源码
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>