Apache Maven快速入门教程
构建软件项目典型有这样几个任务组成:下载依赖,在classpath下放置额外的jar包,编译原程序至二进制代码,运行测试,打包编译代码至可部署的构件,如jar、war、zip文件,然后部署这些构件到应用服务器或仓库中。
Apache Maven可以自动完成这些任务,最大化避免人为手工构建软件造成错误,并将编译和打包代码的工作与代码构建工作分离开来。本文介绍强大的构建工具maven,它用于描述、构建和管理Java软件项目,使用XML编写核心信息——————项目对象模型(Project Object Model, POM)。
1. maven主要特征
maven的主要特征:
-
遵循最佳实践简化项目设置:maven通过提供项目模板(archetype)尽可能减少配置。
-
依赖管理:包括自动更新,下载和验证兼容性,以及报告依赖项闭包(也称为传递依赖项)
-
隔离项目依赖和插件依赖:使用maven,项目依赖是从依赖仓库中获取,而任何插件依赖从插件仓库中获取,这样插件下载额外依赖时很少会冲突。
-
中心仓库系统:项目依赖可以能本地文件系统加载,也可以从公共仓库下载,也就是Maven Central。
2. Project Object Model(项目对象模型)
配置maven项目需要通过Project Object Model(项目对象模型),即通过pom.xml文件进行表示。pom描述项目、管理依赖、配置构建项目的插件。
pom也定义项目中多个模块之间的关系,下面看pom文件的基本结构:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.groupname</groupId>
<artifactId>org.artifactname</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>org.projectname</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
//...
</plugin>
</plugins>
</build>
</project>
下面详细说明这些结构。
2.1 项目标识符
maven使用一组标识符(也称为坐标)唯一表示一个项目,并指定项目构件如何被打包:
groupId – 创建项目的公司或组织的唯一名称,如com.groupname
artifactId – 项目的唯一名称
version – 项目的版本
packaging – 打包方式 (如:WAR/JAR/ZIP)
前三个 (groupId:artifactId:version) 组合形成唯一标识,也是我们使用外部依赖的机制。
2.2 依赖
项目使用外部库称为依赖。maven的依赖管理特性保障自动从中央仓库下载这些依赖,因此本地不再必须存储它们。maven的一个主要特征是带来下列优势:
- 远程依赖库下载数量显著减少,使用更少的存储空间
- 签出项目更快
- 提供高效平台在组织内外交换二进制构件,无需每次都从源代码构建
为了在外部库声明依赖,需要提供构件的groupId, artifactId, version 。请看示例:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
当maven处理依赖时,会下载spring core 包到本地maven仓库。
2.3 仓库
仓库是maven用于容纳构建工件(构件)和各种类型依赖。缺省本地仓库位于用户的主目录中 .m2/repository
文件夹。
如果构件或插件在本地仓库中,maven会从本地加载。否则从中央仓库下载并存储至本地仓库,缺省中央仓库为 maven central。
一些库,如JBoss不在中央仓库,但其它仓库中有。因此需要设置多个远程仓库。有时我们为了提供下载速度,也设置阿里云仓库:
<repositories>
<repository>
<id>JBoss repository</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>nexus-aliyun</id>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</repository>
</repositories>
当然实际应用中一般在maven的setting中进行全局设置。
2.4 属性
自定义属性让pom.xml文件更易读和易维护。通常我们自定义项目依赖库版本作为属性提升可维护行。mavne属性是值占位符形式。pom中任何地方通过${name}方式访问,name为属性名称。
<properties>
<spring.version>4.3.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
如果你想升级Spring版本,仅需要修改该属性值,则所有使用的地方自动更新。属性也通常用于定义构件路径变量:
<properties>
<project.build.folder>${project.build.directory}/tmp/</project.build.folder>
</properties>
<plugin>
//...
<outputDirectory>${project.resources.build.folder}</outputDirectory>
//...
</plugin>
2.5 构建
构建是pom中非常重要部分。它提供缺省maven 目标(goal)信息,构建项目目录,以及应用最终名称。缺省构建部分如下:
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${artifactId}-${version}</finalName>
<filters>
<filter>filters/filter1.properties</filter>
</filters>
//...
</build>
缺省编译构件的输出目录为target,最终打包构件名称是有artifactId 和 version组成,当然也可以修改。
2.6 profile
maven另一个重要特征是profile,它是一组配置值。通过使用profile,可以定制不同环境的构建,如生产/测试/开发:
<profiles>
<profile>
<id>production</id>
<build>
<plugins>
<plugin>
//...
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
//...
</plugin>
</plugins>
</build>
</profile>
</profiles>
上面示例,缺省profile设置为development。如果想运行production profile,使用下面命令:
mvn clean install -Pproduction
3. maven 构建生命周期
每个maven构建遵循特定生命周期,我们可以执行构建中的几个目标,包括编译代码(compile ),打包(package),上传至本地仓(install)。
3.1 生命周期阶段
下面列出最重要的maven声明周期阶段:
validate – 检查项目正确性
compile – 编译源代码至二进制文件
test – 执行单元测试
package – 打包编译代码为构件文件
integration-test – 执行集成测试,如需要打包的其他测试。
verify – 检查包是否有效
install – 安装包文件至本地仓库
deploy – 部署包文件至远程仓库
3.2 插件和目标
maven插件是一个或多个目标集合。目标执行具体任务,目标在阶段中执行,从而决定目标的执行顺序。maven官方提供很多插件。
为了执行上节中提到的阶段,需执行下列命令:
mvn <phase>
举例,mvn clean install
。则会删除前面生成的jar/war/zip文件,然后执行install阶段之前的所有目标,编译、打包、安装等。
请注意,插件提供的目标可以与生命周期的不同阶段相关联,从而能够复用代码。
4. 第一个maven项目示例
本节使用maven的命令行功能创建Java项目。
4.1 生成简单的java项目
运行下面命令生成简单Java项目:
mvn archetype:generate -DgroupId=org.dataz -DartifactId=firstprj -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
groupId 指定创建项目的组织,通常是公司域名的反向形式。artifactId 项目中基本包名,这里使用标准生成代码原型。因为没有指定版本,则使用缺省版本1.0-SNAPSHOT,打包方式设置为jar。
如果想知道参数具体值,我们可以设置interactiveMode=true,这样maven会询问所有必要的参数。命令执行完成后,生成一个java项目, src/main/java目录包括App.java类,其中包括简单的Hello World程序。同时也有一个示例测试类在src/test/java目录中,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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dataz</groupId>
<artifactId>firstprj</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>firstprj</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
我们看到默认增加了junit依赖。
4.2 编译打包项目
通过下面命令编译项目:
mvn compile
Maven将运行编译阶段所需的所有阶段以编译项目源代码。如果您只想运行测试阶段,您可以使用:
mvn test
现在执行打包阶段生成编译后jar文件:
mvn package
4.3 执行应用
最后,我们打算执行该项目,需要exec-maven-plugin插件。需要在pom中增加必要的配置:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>com.dataz.App</mainClass>
</configuration>
</plugin>
第一个插件 maven-compiler-plugin负责编译源代码,这里指定版本为1.8。exec-maven-plugin插件运行项目mainClass。通过下面命令执行项目:
mvn exec:java
5. 多模块项目构建
maven处理多模块项目(聚合项目)机制称为反应堆(reactor)。反应堆收集所有要构建模块,然后将模块按照正确的构建顺序排序,最后逐个构建它们。现在看如何创建包括多模块的父项目。
5.1 创建父项目
首先,创建父项目,命名为parent-project,使用下面命令:
mvn archetype:generate -DgroupId=com.dataz -DartifactId=parent-project
然后更新pom.xml文件,指定其为父模块:
<packaging>pom</packaging>
5.2 创建子模块项目
接下来,在parent-project目录中创建子模块项目:
cd parent-project
mvn archetype:generate -DgroupId=com.dataz -DartifactId=core
mvn archetype:generate -DgroupId=com.dataz -DartifactId=service
mvn archetype:generate -DgroupId=com.dataz -DartifactId=webapp
为了验证是否正确创建子模块项目,我们看看文件,应该能看到parent-project项目中的pom.xml文件包括三个模块:
<modules>
<module>core</module>
<module>service</module>
<module>webapp</module>
</modules>
而且,每个子模块的pom.xml文件中都包括父模块:
<parent>
<groupId>com.dataz</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
5.3 父项目中启用依赖管理
依赖管理是集中父模块及其子模块依赖信息的机制。当项目或模块继承共同父项目,可以在父pom.xml中指定必要公共依赖信息,从而简化子模块pom.xml配置。示例:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
//...
</dependencies>
</dependencyManagement>
通过在父模块中声明spring-core版本,所有子模块依赖于spring-core都可以仅使用groupId和artifactId来声明依赖,并且版本将被继承:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
//...
</dependencies>
而且,可以在父模块中提供了排除依赖管理功能,这样特定库将不被子模块继承:
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
如果某子模块需要使用不同版本的依赖,可以在子模块pom.xml中重新指定版本:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
请注意,虽然子模块从父项目继承,但父项目不一定有它聚合的任何模块。另一方面,父项目也可以聚合不从其继承的项目。
5.4 更新子模块并构建项目
我们可以改变每个子模块的包类型。例如,我们修改webapp模块pom.xml设置包类型为war:
<packaging>war</packaging>
现在我们开始项目构建,使用mvn clean install
命令,输出日志类似这样:
[INFO] Scanning for projects...
[INFO] Reactor build order:
[INFO] parent-project
[INFO] core
[INFO] service
[INFO] webapp
//.............
[INFO] -----------------------------------------
[INFO] Reactor Summary:
[INFO] -----------------------------------------
[INFO] parent-project .................. SUCCESS [2.041s]
[INFO] core ............................ SUCCESS [4.802s]
[INFO] service ......................... SUCCESS [3.065s]
[INFO] webapp .......................... SUCCESS [6.125s]
[INFO] -----------------------------------------
6. 总结
本文带你学习maven及其主要概念和常用功能,希望为你后续更深入理解做铺垫。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/109563387