Apache Maven 插件

访问原文:https://www.ibm.com/developerworks/cn/java/j-5things16/index.html

掌握现代 Maven 插件的技巧





您是否知道 Maven?

Maven 是一个面向 Java™开发人员的领先的依赖管理和构建工具,而且名副其实!它通过阐述项目的构造来标准化软件构建流程,将它部署为应用程序,然后与其他项目共享它。

Maven 采用了一组可靠的插件来提供它的所有功能。在 Maven 中,插件拥有目标,在幕后,该目标就是 Java 方法。目标执行构建任务,比如编译项目,打包它,并将它部署到本地或远程服务器。这些活动可完美地映射到构建生命周期的各个阶段。

Maven 提供了自己的构建插件,这些插件已打包且可立即使用,而且预先配置了默认值。通过“约定高于配置”原则,可以确保能够针对给定任务的复杂性来扩展配置。大部分构建任务都只需极少的配置。

您还可以自定义 Maven 插件的行为。使用 Maven 的 <configuration> 元素,很容易重写插件默认值并定义新值。毫无疑问,大部分重写的默认值是 compiler 插件的 <source> 和<target> 值。

需要证据?您有多少次将清单 1 中的 XML 添加到 POM 中,以设置正确的 JVM 版本?

清单 1. compiler 插件中的 Java 版本配置
1
2
3
4
5
6
7
8
9
< plugin >
    < groupId >org.apache.maven.plugins</ groupId >
    < artifactId >maven-compiler-plugin</ artifactId >
    < version >3.6.1</ version >
    < configuration >
        < source >1.8</ source >
        < target >1.8</ target >
    </ configuration >
</ plugin >

执行 Maven 生命周期

每个插件目标都映射到一个 Maven 生命周期阶段。发出 mvn compile 命令会告诉 mvn 实用程序调用绑定到 compile 生命周期阶段的所有目标。compiler 插件的 compile 目标被绑定到这个生命周期阶段。

阶段与目标之间是一对多的关系。多个插件目标可以绑定到同一个阶段,以形成相关任务集合。阶段也是分层的,这意味着执行一个阶段会导致执行它前面的所有阶段

在本例中,发出 mvn compile 命令会启动 validate 阶段(Maven 的默认构建生命周期的第一个阶段),并调用绑定到该阶段的所有目标。

Maven 和 Google Code 网站维护着一个 Maven 插件列表。这些插件提供了各种各样有用且省时的功能,您可以将它们整合到构建流程中。我将介绍我发现的一些最有用的插件,并展示如何最充分地利用它们。

1.对 JAR 或 WAR 执行数字签名

单击下面的按钮,下载本示例的代码。它包含一个简单的应用程序和一个包含已配置好的 Jarsigner 插件的 POM 文件。

获取代码

对 JAR 或 WAR 执行数字签名是一项重要任务,尤其是在您想分发您的应用程序的时候。幸运的是,Java 平台提供了一个名为 jarsigner 的存档签名实用程序。它是一个命令行工具,可通过向它传递存档文件的位置和各种参数(比如包含您的加密密钥的密钥库)对存档文件执行签名。

可以在 JDK 安装的 <%JAVA_HOME%>/bin 目录中找到 jarsigner。清单 2 展示了如何使用此实用程序对 JAR 执行签名。

清单 2. 使用 jarsigner 实用程序对存档文件执行签名
1
2
3
4
5
6
jarsigner
     -keystore /path/to/keystore.jks
     -storepass < password >
     -keypass < key password>
     YourArchive.jar
     alias

jarsigner 是一个易于使用的命令行工具,而且开箱即用。 如果能自动化签名流程,在构建周期的 package 阶段对存档文件执行签名岂不是更好? 得益于包含 jarsigner 实用程序的 Maven Jarsigner 插件,您可以实现此目标。您只需要将该插件的 sign 目标绑定到您的构建周期的 package 阶段。

首先需要一个密钥库。如果没有,可以使用 Java 平台的 keytool 实用程序创建它,该实用程序可在 JDK 安装的<%JAVA_HOME%>/bin 目录中找到。

创建一个密钥库

要创建一个密钥库,请导航到您想要放置它的位置并执行清单 3 中的命令。一定要将 KeyAlias 替换为合适的值,比如您的域名。官方 Oracle 文档详细介绍了该工具接受的更多配置选项。

清单 3. 为 jarsigner 实用程序创建一个密钥库
1
keytool -genkey -alias < KeyAlias > -keyalg RSA -keystore keystore.jks -keysize 2048

创建密钥库的过程要求您回答一系列有关您自己和您的组织的问题,并提供一个安全密码。配置 Maven Jarsigner 插件时(接下来就会这么做)将需要此密码。

将 Jarsigner 添加到您的构建流程中

现在将 Maven Jarsigner 插件添加到您的构建生命周期中,然后配置它来对 package 阶段中生成的 JAR 执行数字签名。关联到此阶段是合理的,因为已构造 JAR 并将它存储在您项目的默认输出目录中,该目录通常是 target 目录。在 POM 文件的 <plugins> 部分,添加清单 4 中所示的代码。

清单 4. 添加 Jarsigner 插件
1
2
3
4
5
< plugin >
    < groupId >org.apache.maven.plugins</ groupId >
    < artifactId >maven-jarsigner-plugin</ artifactId >
    < version >1.4</ version >
</ plugin >

您想要在构建 JAR 后对它执行签名,所以需要将签名过程(包装在 sign 目标中)连接到 package 生命周期阶段。为此,请将清单 5 中的代码添加到该插件中。

清单 5. 将 sign 目标连接到 package 阶段
1
2
3
4
5
6
7
8
9
< executions >
     < execution >
         < id >sign</ id >
         < phase >package</ phase >
         < goals >
             < goal >sign</ goal >
         </ goals >
     </ execution >
</ executions >

sign 目标需要一些配置细节才能对 JAR 执行数字签名。所以应该在 <configuration> 元素之间添加密钥库位置、您想要使用的凭证的别名、密钥库密码和凭证的密码,如清单 6 所示。

清单 6. 指定安全凭证
1
2
3
4
5
6
< configuration >
    < keystore >/location/of/keystore.jks</ keystore >
    < alias >KeyAlias</ alias >
    < storepass >password</ storepass >
    < keypass >password</ keypass >
</ configuration >

这是实现 JAR 签名特性所需的最低配置。请注意,该插件提供了大量额外的配置选项供选择。

最后一步是构建 JAR 并验证已对它正确执行签名。从命令行执行 package 目标,如下所示:mvn clean package。在控制台输出中,会看到 JAR 正在构建,然后被签名。图 1 展示了您可能看到的结果

图 1. 输出显示已对存档执行签名
输出显示已对存档执行签名

将 JAR 构建到 target 输出目录中,这是 Jarsigner 插件期望找到它的位置。该插件将使用您提供的凭证对 JAR 执行签名,然后向 META-INF 目录添加两个额外的文件:一个具有 .SF 扩展名的签名文件,以及一个具有 .RSA 扩展名的签名块文件。

现在已有一个经过数字签名的 JAR 可供分类。

验证数字签名

在分类 JAR 之前,让我们验证已对它进行正确签名。可以使用 Maven Jarsigner 的 verify 目标,或者使用 jarsigner 工具通过命令行来实现此操作。在清单 7 中,我使用了命令行工具并向它传递我想要验证的存档文件。

清单 7. 使用 jarsigner 实用程序验证已签名的 JAR
1
jarsigner -verify target/YourJavaArchive.jar

如果成功,则会收到以下消息:jar verified

对 WAR 文件执行签名

对 JAR 执行签名不是 Jarsigner 的唯一功能。该插件可对任何 Java 存档文件执行签名,包括 WAR 文件。要查看此操作是如何实现的,可以将 POM 的打包类型从 JAR 更改为 WAR,添加 Maven WAR 插件(如清单 8 所示)并执行命令:mvn clean package

清单 8. 添加 Maven WAR 插件
1
2
3
4
5
< plugin >
    < groupId >org.apache.maven.plugins</ groupId >
    < artifactId >maven-war-plugin</ artifactId >
    < version >3.1.0</ version >
</ plugin >

检查 target 目录,您会找到已签名的 WAR 文件。

对多个存档文件执行签名

如果有多个存档文件要签名,Jarsigner 也能应对这种情况。清单 9 中的代码将 JAR 的签名位置指定为 target/all,并且将对此目录中的所有 JAR 执行签名。

清单 9. 指定一个存档目录
1
< archiveDirectory >target/all</ archiveDirectory >

如果需要更精确地控制要签名的存档文件,可以使用通配符来显式包含和排除文件,如清单 10 所示。

清单 10. 包含和排除选定的存档文件
1
2
3
4
5
6
< includes >
    < include >*1.0.jar</ include >
</ includes >
< excludes >
    < exclude >*SNAPSHOT.jar</ exclude >
</ excludes >

2.使用 Maven Cargo 部署一个受保护的 Web 应用程序

单击下面的按钮,下载本示例的代码。它包含一个简单的 Web 应用程序和一个包含已配置好的 Cargo 插件的 POM 文件。

获取代码

来自 Codehaus 的 Cargo 插件 是 Cargo API 的一个包装器。该 API 旨在配置、启动、停止应用程序并将它部署到各种受支持的容器中,并解析、创建和合并 Java EE 模块。

一个特别重要的特性是,Cargo 能够采用容器不可知的方式来指定服务器属性。这些属性包括端口、远程安全凭证、JVM 参数,以及(我们最感兴趣的)您想部署的应用程序的用户登录细节。该插件支持 14 种最流行的服务器的最新版本。

Cargo 插件最好关联到 Maven 生命周期的 package 阶段中。也可以直接引用 run 目标来独立执行它:mvn cargo:run。独立执行会假设该项目已打包且准备好部署。

我们首先将 Cargo 的 run 目标关联到 package 阶段中,如清单 11 所示。

清单 11. 将 Cargo 的 run 目标关联到 package 阶段
1
2
3
4
5
6
7
8
9
10
11
12
13
< plugin >
    < groupId >org.codehaus.cargo</ groupId >
    < artifactId >cargo-maven2-plugin</ artifactId >
    < version >1.6.4</ version >
    < executions >
        < execution >
            < phase >package</ phase >
            < goals >
                < goal >run</ goal >
            </ goals >
        </ execution >
    </ executions >
</ plugin >

完成 Maven 集成后,现在需要对您希望 Cargo 部署应用程序的目标容器进行配置。Cargo 支持各种各样的容器场景,包括部署到已在运行的本地或远程服务器(这包括在需要时启动该服务器)。或者,可以配置 Cargo 来下载、安装、部署并启动它支持的 14 种服务器中的任意一种。

对于本示例,我将使用 IBM® WebSphere® Liberty,我已下载它并解压到一个名为 servers 的目录中。

容器配置至少需要容器 ID 和所安装服务器的主目录位置。清单 12 给出了位于我的 servers/wlp 目录中的 Liberty 服务器的配置。

清单 12. 容器配置
1
2
3
4
5
6
< configuration >
    < container >
        < containerId >liberty</ containerId >
        < home >\path\to\servers\wlp</ home >
    </ container >
</ configuration >

下载容器 ZIP 文件

另一个选项是指定 IBM 网站上的 Liberty ZIP 文件的 URL,在这种情况下,Cargo 插件会下载并安装该服务器。清单 13 显示了执行此操作的代码。

清单 13. 从网络安装容器
1
2
3
4
5
6
7
8
9
10
11
12
< container >
    < containerId >liberty</ containerId >
    < zipUrlInstaller >
        < url >
               https://public.dhe.ibm.com/ibmdl/export/pub/
               software/websphere/wasdev/downloads/wlp/17.0.0.2/
               wlp-webProfile7-17.0.0.2.zip
        </ url >
        < downloadDir >/path/to/downloadDir</ downloadDir >
        < extractDir >/path/to/extractDir</ extractDir >
    </ zipUrlInstaller >
</ container >

第一次执行 run 目标时,会下载和解压 ZIP 文件。在后续执行时,Maven 会检测到该文件已下载和安装,并跳过该任务。

您现在拥有最少的配置,可以将该应用程序部署到您的服务器中来测试该配置。通过调用 package 阶段 (mvn package) 来启动该流程。将应用程序编译、打包并部署到服务器中,而且可通过以下 URL 访问它:http://localhost:8080/{artifactid}/index.html

自定义上下文根目录

默认情况下,使用 artifactid 来命名 Web 应用程序的上下文根目录。在某些情况下,您需要指定一个自定义上下文根目录。在清单 14 中,我将上下文根目录定义为 home

清单 14. 自定义上下文根目录
1
2
3
4
5
6
7
< deployables >
    < deployable >
        < properties >
            < context >home</ context >
        </ properties >
    </ deployable >
</ deployables >

部署应用程序后,可通过以下地址访问该 Web 应用程序: localhost:8080/home/index.html

指定用户登录信息

您现在已有一个非常可靠的部署流程,它会下载并安装一个服务器,将您的应用程序部署到一个自定义上下文根目录中。对于 Cargo 插件的功能而言,这才刚刚开始。

在我们开始定义配置属性时,Cargo 才真正发挥出它的实力。正如我之前提到的,这些配置属性是容器的属性,比如端口、协议,最重要的是用户登录细节。

让我们向示例应用程序添加一个用户,并强制登录到该站点。为了保持简单,我们将使用基本身份验证方法,只需要应用程序的 web.xml 文件中的极少配置。清单 15 显示了 user-role 的规范和对 WelcomeServlet Web 资源的限制。

清单 15. 声明用户角色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
< web-app version = "3.1" ...>
 
    < security-constraint >
        < web-resource-collection >
            < web-resource-name >Welcome Servlet</            <web-resource-name>Welcome Servlet</web-resource-name>
            < url-pattern >/WelcomeServlet/*</ url-pattern >
url-pattern >/WelcomeServlet/*</ url-pattern >
            < http-method >GET</ http-method >
        </ >
相关文章
相关标签/搜索