第五十二章. Maven 插件

Chapter 52. The Maven Plugin

本章还在完善中。
This chapter is a work in progress

Maven 插件添加了将项目部署到 Maven 仓库的支持。
The Maven plugin adds support for deploying artifacts to Maven repositories.

52.1. 用法

52.1. Usage

要使用 Maven 插件,请在构建脚本中包含:
To use the Maven plugin, include in your build script:

示例 52.1. 使用 Maven 插件 - Example 52.1. Using the Maven plugin

build.gradle

apply plugin: 'maven'

52.2. 任务

52.2. Tasks

Maven 插件定义了以下任务:
The Maven plugin defines the following tasks:

表 52.1. Maven 插件——任务 - Table 52.1. Maven plugin - tasks

任务名称
Task name
依赖于
Depends on
类型
Type
描述
Description
install 所有构建关联归档的任务。
All tasks that build the associated archives.
Upload 将相关的工件安装到本地的 Maven 缓存,包括Maven 元数据的生成。默认情况下,安装任务是与 archives 配置相关联的。这个配置在默认情况下只将默认的 jar 作为元素。要了解有关安装到本地仓库的更多信息,请参阅:第 52.6.3 节,《安装到本地存储库》
Installs the associated artifacts to the local Maven cache, including Maven metadata generation. By default the install task is associated with the archives configuration. This configuration has by default only the default jar as an element. To learn more about installing to the local repository, see: Section 52.6.3, “Installing to the local repository”

52.3. 依赖管理

52.3. Dependency management

Maven 插件没有定义任何依赖配置。
The Maven plugin does not define any dependency configurations.

52.4. 约定属性

52.4. Convention properties

Maven 插件定义了下列约定属性:
The Maven plugin defines the following convention properties:

表 52.2. Maven 插件——属性 - Table 52.2. Maven plugin - properties

属性名称
Property name
类型
Type
默认值
Default value
描述
Description
pomDirName String poms 用于写入生成的 POM 的文件夹路径,相对于构建目录。
The path of the directory to write the generated POMs, relative to the build directory.
pomDir 文件(只读)
File (read-only)
buildDir/pomDirName 生成的 POM 的写入目录。
The directory where the generated POMs are written to.
conf2ScopeMappings Conf2ScopeMappingContainer n/a 将 Gradle 配置映射到 Maven 作用域的说明。见第 52.6.4.2 节,《依赖映射》
Instructions for mapping Gradle configurations to Maven scopes. See Section 52.6.4.2, “Dependency mapping”.

这些属性由一个MavenPluginConvention 约定对象提供。
These properties are provided by a MavenPluginConvention convention object.

52.5. 约定方法

52.5. Convention methods

Maven 插件提供了用于创建 POM 的工厂方法,如果你在不上传到 Maven 仓库的情况下需要 POM 文件,这个工厂方法将非常有用。
The maven plugin provides a factory method for creating a POM. This is useful if you need a POM without the context of uploading to a Maven repo.

示例 52.2. 创建一个单独的 pom。 - Example 52.2. Creating a stand alone pom.

build.gradle

task writeNewPom << {
    pom {
        project {
            inceptionYear '2008'
            licenses {
                license {
                    name 'The Apache Software License, Version 2.0'
                    url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    distribution 'repo'
                }
            }
        }
    }.writeTo("$buildDir/newpom.xml")
}

在其他方面,Gradle 支持和 polyglot Maven 相同的生成器语法。要了解有关 Gradle Maven POM 对象的更多信息,请参阅MavenPom。另请参见:MavenPluginConvention
Amongst other things, Gradle supports the same builder syntax as polyglot Maven. To learn more about the Gradle Maven POM object, see MavenPom. See also: MavenPluginConvention

52.6. 与 Maven 仓库的交互

52.6. Interacting with Maven repositories

52.6.1. 导言

52.6.1. Introduction

通过 Gradle,你可以部署到远程 Maven 仓库或是安装到本地 Maven 仓库。这包括所有 Maven 元数据的操作,并且 Maven 快照也可以用。实际上,Gradle 的部署是 100% 兼容 Maven 的,因为我们在本质上使用的是原生 Maven Ant 任务。
With Gradle you can deploy to remote Maven repositories or install to your local Maven repository. This includes all Maven metadata manipulation and works also for Maven snapshots. In fact, Gradle's deployment is 100 percent Maven compatible as we use the native Maven Ant tasks under the hood.

如果你没有 POM,部署到 Maven 仓库只有一半的乐趣。幸运的是 Gradle 可以使用它的依赖信息为你生成这个 POM。
Deploying to a Maven repository is only half the fun if you don't have a POM. Fortunately Gradle can generate this POM for you using the dependency information it has.

52.6.2. 部署到 Maven 仓库

52.6.2. Deploying to a Maven repository

让我们假设你的项目只生成默认的 jar 文件,现在你想将这个 jar 文件部署到远程 Maven 仓库。
Let's assume your project produces just the default jar file. Now you want to deploy this jar file to a remote Maven repository.

示例 52.3. 上传文件到远程 Maven 仓库 - Example 52.3. Upload of file to remote Maven repository

build.gradle

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
}

调用 uploadArchives 任务将生成 POM,并将工件和 POM 部署到指定的仓库。
That is all. Calling the uploadArchives task will generate the POM and deploys the artifact and the POM to the specified repository.

如果你需要对 file 以外的其他协议支持,那么还要再做一些事情。在这种情况下,我们委派的本地 Maven 代码需要其他的库。具体是哪些库,则取决于你需要的协议。表 52.3,“用于Maven部署的协议 jar” 中列出了可用的协议和相应的库(这些库有传递依赖,而这些依赖也有其自己的传递依赖)。 [19] 例如,要使用 SSH 协议,你可以执行以下操作:
There is some more work to do if you need support for other protocols than file. In this case the native Maven code we delegate to needs additional libraries. Which libraries depend on the protocol you need. The available protocols and the corresponding libraries are listed in Table 52.3, “Protocol jars for Maven deployment” (those libraries have again transitive dependencies which have transitive dependencies). [19] For example to use the ssh protocol you can do:

示例 52.4. 通过 SSH 上传文件 - Example 52.4. Upload of file via SSH

build.gradle

configurations {
    deployerJars
}

repositories {
    mavenCentral()
}

dependencies {
    deployerJars "org.apache.maven.wagon:wagon-ssh:2.2"
}

uploadArchives {
    repositories.mavenDeployer {
        configuration = configurations.deployerJars
        repository(url: "scp://repos.mycompany.com/releases") {
            authentication(userName: "me", password: "myPassword")
        }
    }
}

Maven 部署器有许多配置选项,配置通过 Groovy 构建器完成。配置树的所有元素都是 Java bean。你可以传一个 map 到 bean 元素来配置简单的属性。如果要将其他 bean 元素添加到其 parent,可以使用闭包。在上面的示例中,repositoryauthentication 都是这样的 bean 元素。表 52.4,“MavenDeployer的配置元素” 列出了可用的 bean 元素以及对应类的 javadoc 链接。在 javadoc 中,你可以查看能够为特定元素设置的属性。
There are many configuration options for the Maven deployer. The configuration is done via a Groovy builder. All the elements of this tree are Java beans. To configure the simple attributes you pass a map to the bean elements. To add another bean elements to its parent, you use a closure. In the example above repository and authentication are such bean elements. Table 52.4, “Configuration elements of the MavenDeployer” lists the available bean elements and a link to the javadoc of the corresponding class. In the javadoc you can see the possible attributes you can set for a particular element.

在 Maven 中,你可以定义普通仓库和可选的快照仓库。如果没有定义快照仓库,那么发行版和快照都会部署到 repository 元素中。否则,快照将部署到 snapshotRepository 元素。
In Maven you can define repositories and optionally snapshot repositories. If no snapshot repository is defined, releases and snapshots are both deployed to the repository element. Otherwise snapshots are deployed to the snapshotRepository element.

表 52.3. Maven 部署的协议 jar - Table 52.3. Protocol jars for Maven deployment

协议
Protocol

Library
http org.apache.maven.wagon:wagon-http:2.2
ssh org.apache.maven.wagon:wagon-ssh:2.2
ssh-external org.apache.maven.wagon:wagon-ssh-external:2.2
ftp org.apache.maven.wagon:wagon-ftp:2.2
webdav org.apache.maven.wagon:wagon-webdav:1.0-beta-2
file -

表 52.4. MavenDeployer 的配置元素 - Table 52.4. Configuration elements of the MavenDeployer

52.6.3. 安装到本地仓库

52.6.3. Installing to the local repository

Maven 插件向项目添加 install 任务。这个任务依赖于 archives 配置的所有归档任务。它将这些归档安装到本地 Maven 仓库中。Maven settings.xml 中是否重新定义了本地仓库的默认位置,该任务也会考虑到。
The Maven plugin adds an install task to your project. This task depends on all the archives task of the archives configuration. It installs those archives to your local Maven repository. If the default location for the local repository is redefined in a Maven settings.xml, this is considered by this task.

52.6.4. Maven POM 生成

52.6.4. Maven POM generation

当部署一个工件到 Maven 仓库时,Gradle 会自动为它生成一个 POM。下表展示了用于 POM 的 groupIdartifactIdversionpackage 元素的默认值。dependency 元素则是根据项目的依赖声明来创建的。
When deploying an artifact to a Maven repository, Gradle automatically generates a POM for it. The groupId, artifactId, version and packaging elements used for the POM default to the values shown in the table below. The dependency elements are created from the project's dependency declarations.

表 52.5. Maven POM 生成的默认值 - Table 52.5. Default Values for Maven POM generation

Maven 元素
Maven Element
默认值
Default Value
groupId project.group
artifactId uploadTask.repositories.mavenDeployer.pom.artifactId (if set) or archiveTask.baseName.
version project.version
packaging archiveTask.extension

在这里,uploadTaskarchiveTask 分别指的是用于上传和生成归档的任务(例如,uploadArchivesjar)。archiveTask.baseName 默认为 project.archivesBaseName ,后者默认为 project.name
Here, uploadTask and archiveTask refer to the tasks used for uploading and generating the archive, respectively (for example uploadArchives and jar). archiveTask.baseName defaults to project.archivesBaseName which in turn defaults to project.name.

当你把 archiveTask.baseName 设置为非默认值时,请确保将 uploadTask.repositories.mavenDeployer.pom.artifactId 设置为相同的值。否则在同一个构建中,其他项目引用到的这个项目所生成的 POM 的 artifact ID 可能会有误。
When you set archiveTask.baseName to a value other than the default, make sure to set uploadTask.repositories.mavenDeployer.pom.artifactId to the same value. Otherwise, the project at hand may be referenced with the wrong artifact ID from generated POMs for other projects in the same build.

生成的 POM 可以在 <buildDir>/poms 中找到。它们可以通过 MavenPom API 进一步自定义。比如,你可能希望部署到 Maven 仓库的工件版本或名称与 Gradle 生成的工件不同。要自定义这些内容,你可以这样做:
Generated POMs can be found in <buildDir>/poms. They can be further customized via the MavenPom API. For example, you might want the artifact deployed to the Maven repository to have a different version or name than the artifact generated by Gradle. To customize these you can do:

示例 52.5. pom 的定制 - Example 52.5. Customization of pom

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            pom.version = '1.0Maven'
            pom.artifactId = 'myMavenName'
        }
    }
}

如果要将其他内容添加到 POM,可以用 pom.project 构建器。通过这个构建器,Maven POM 参考 中所列出的任何元素都可以被添加进来。
To add additional content to the POM, the pom.project builder can be used. With this builder, any element listed in the Maven POM reference can be added.

示例 52.6. pom 的构建器样式自定义 - Example 52.6. Builder style customization of pom

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            pom.project {
                licenses {
                    license {
                        name 'The Apache Software License, Version 2.0'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        distribution 'repo'
                    }
                }
            }
        }
    }
}

注:groupIdartifactIdversionpackaging 应该始终在 pom 对象上直接设置。
Note: groupId, artifactId, version, and packaging should always be set directly on the pom object.

示例 52.7. 修改自动生成的内容 - Example 52.7. Modifying auto-generated content

build.gradle

def installer = install.repositories.mavenInstaller
def deployer = uploadArchives.repositories.mavenDeployer

[installer, deployer]*.pom*.whenConfigured {pom ->
    pom.dependencies.find {dep -> dep.groupId == 'group3' && dep.artifactId == 'runtime' }.optional = true
}

如果要发布多个工件,那么要做的事情会有些不同。请参阅第 52.6.4.1 节,“每个项目多个工件”
If you have more than one artifact to publish, things work a little bit differently. SeeSection 52.6.4.1, “Multiple artifacts per project”.

要自定义 Maven 安装器(见第 52.6.3 节,“安装到本地仓库”)的设置,你可以:
To customize the settings for the Maven installer (seeSection 52.6.3, “Installing to the local repository”), you can do:

示例 52.8. Maven 安装器的自定义 - Example 52.8. Customization of Maven installer

build.gradle

install {
    repositories.mavenInstaller {
        pom.version = '1.0Maven'
        pom.artifactId = 'myName'
    }
}

52.6.4.1. 每个项目多个构件

52.6.4.1. Multiple artifacts per project

Maven 对每个项目只能处理一个工件,这反映在 Maven POM 的结构中。我们认为,在许多情况下,每个项目有一个以上的工件是有意义的。在这种情况下,你需要生成多个 POM。在这种情况下,你必须显式声明要发布到 Maven 仓库的每个工件。MavenDeployer 和 MavenInstaller 都为此提供了 API:
Maven can only deal with one artifact per project. This is reflected in the structure of the Maven POM. We think there are many situations where it makes sense to have more than one artifact per project. In such a case you need to generate multiple POMs. In such a case you have to explicitly declare each artifact you want to publish to a Maven repository. The MavenDeployer and the MavenInstaller both provide an API for this:

示例 52.9. 多个 pom 的生成 - Example 52.9. Generation of multiple poms

build.gradle

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
            addFilter('api') {artifact, file ->
                artifact.name == 'api'
            }
            addFilter('service') {artifact, file ->
                artifact.name == 'service'
            }
            pom('api').version = 'mySpecialMavenVersion'
        }
    }
}

你需要为每个要发布的工件声明一个过滤器,这个过滤器定义了其接受 Gradle 工件的布尔表达式。每个过滤器都有一个与之关联的 POM,通过它你可以进行配置。要了解更多信息,请查看 PomFilterContainer 及其关联的类。
You need to declare a filter for each artifact you want to publish. This filter defines a boolean expression for which Gradle artifact it accepts. Each filter has a POM associated with it which you can configure. To learn more about this have a look at PomFilterContainer and its associated classes.

52.6.4.2. 依赖映射

52.6.4.2. Dependency mapping

Maven 插件配置了由 Java 和 War 插件添加的 Gradle 配置与 Maven 作用域之间的默认映射。大多数时候,你不需要去接触它,并且你可以安全跳过本节内容。映射过程如下。你可以把一个配置只映射到一个作用域上,也可以将不同的配置映射到一个或多个作用域上。另外,还可以对特定的配置与作用域的映射指定优先级。你可以参考 Conf2ScopeMappingContainer 来了解更多信息。要访问映射配置,你可以:
The Maven plugin configures the default mapping between the Gradle configurations added by the Java and War plugin and the Maven scopes. Most of the time you don't need to touch this and you can safely skip this section. The mapping works like the following. You can map a configuration to one and only one scope. Different configurations can be mapped to one or different scopes. One can assign also a priority to a particular configuration-to-scope mapping. Have a look at Conf2ScopeMappingContainer to learn more. To access the mapping configuration you can say:

示例 52.10. 访问映射配置 - Example 52.10. Accessing a mapping configuration

build.gradle

task mappings << {
    println conf2ScopeMappings.mappings
}

如果有可能,Gradle 的排除规会转换为 Maven 的排除规则。如果在 Gradle 排除规则中指定了组及模块名称的话(与 Ivy 相反,Maven对这两个都需要),那么这种转换是可能的。对配置的排除规则如果可以被转换的话,也会包含在 Maven POM 中。
Gradle exclude rules are converted to Maven excludes if possible. Such a conversion is possible if in the Gradle exclude rule the group as well as the module name is specified (as Maven needs both in contrast to Ivy). Per-configuration excludes are also included in the Maven POM, if they are convertible.



[19] 已经计划在将来的发行版中为其提供开箱即用的支持。
[19] It is planned for a future release to provide out-of-the-box support for this