Skip to main content
 首页 » 编程设计

Apache Maven快速入门教程

2022年07月19日116itcoder

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