阿帕奇 maven教程

    技术2024-01-26  101

    Maven是Java™开发人员的出色构建工具,您也可以使用它来管理项目的生命周期。 作为生命周期管理工具,Maven跨阶段运行,而不是Ant风格的构建“任务”。 Maven处理项目生命周期的所有阶段,包括验证,代码生成,编译,测试,打包,集成测试,验证,安装,部署以及项目站点的创建和部署。

    要了解Maven与传统构建工具之间的区别,请考虑构建JAR文件和EAR文件的过程。 使用Ant,您需要定义特定的任务来组装每个工件。 另一方面,Maven可以为您完成大部分工作:您只需告诉它项目是JAR还是EAR文件,然后指示它处理“打包”阶段即可。 Maven将找到所需的资源并构建文件。

    您会发现许多入门指南,这些入门指南包括在本文的“ 相关主题”部分中列出的一些指南。 这里的五个技巧旨在帮助您了解接下来的内容:使用Maven管理应用程序生命周期时出现的编程方案。

    1.可执行的JAR文件

    关于本系列

    所以您认为您了解Java编程吗? 事实是,大多数开发人员从头开始学习Java平台,仅学习足够的知识即可完成工作。 在这个正在进行的系列文章中,Java技术专家深入探讨了Java平台的核心功能,并提出了一些技巧和窍门,这些技巧和窍门甚至可以帮助您解决最棘手的编程挑战。

    使用Maven构建JAR文件非常容易:只需将项目包装定义为“ jar”,然后执行包装生命周期阶段即可。 但是定义可执行的JAR文件更加棘手。 有效地执行此操作涉及以下步骤:

    在您的JAR的MANIFEST.MF文件中定义一个main类,该main类定义了可执行类。 (MANIFEST.MF是打包应用程序时Maven生成的文件。) 查找项目依赖的所有库。 将那些库包括在MANIFEST.MF文件中,以便您的应用程序类可以找到它们。

    您可以手动完成所有这些操作,也可以在两个Maven插件( maven-jar-plugin和maven-dependency-plugin的帮助下更有效地进行操作。

    maven-jar-plugin

    maven-jar-plugin做很多事情,但是在这里我们感兴趣的是使用它来修改默认MANIFEST.MF文件的内容。 在POM文件的插件部分中,添加清单1中所示的代码:

    清单1.使用maven-jar-plugin修改MANIFEST.MF
    <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>com.mypackage.MyClass</mainClass> </manifest> </archive> </configuration> </plugin>

    所有Maven插件都通过<configuration>元素公开其配置。 在此示例中, maven-jar-plugin修改了其archive属性,特别是存档的manifest属性,该属性控制MANIFEST.MF文件的内容。 它包括三个元素:

    addClassPath :将此元素设置为true可以告诉maven-jar-plugin将一个Class-Path元素添加到MANIFEST.MF文件,并在该Class-Path元素中包括所有依赖项 classpathPrefix :如果计划将所有依赖项与要构建的JAR包含在同一目录中,则可以忽略此元素; 否则,请使用classpathPrefix指定所有相关JAR文件的前缀。 在清单1中, classpathPrefix指定所有依赖项应位于相对于归档文件的“ lib ”文件夹中。 mainClass :使用此元素定义当用户使用java -jar命令执行JAR文件时要执行的类的名称。

    Maven依赖插件

    使用这三个元素配置MANIFEST.MF文件后,下一步是实际将所有依赖项复制到lib文件夹。 为此,您使用了maven-dependency-plugin ,如清单2所示:

    清单2.使用maven-dependency-plugin将依赖项复制到lib
    <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy</id> <phase>install</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory> ${project.build.directory}/lib </outputDirectory> </configuration> </execution> </executions> </plugin>

    maven-dependency-plugin具有copy-dependencies目标,该目标会将您的依赖关系复制到您选择的目录中。 在此示例中,我将依赖项复制到了build目录( project-home/target/lib )下的lib目录。

    有了依赖关系并修改了MANIFEST.MF后,您可以使用简单的命令启动应用程序:

    java -jar jarfilename.jar

    2.自定义MANIFEST.MF

    尽管maven-jar-plugin允许您修改MANIFEST.MF文件的公共部分,但有时您需要更自定义的MANIFEST.MF。 解决方案有两个:

    在“模板” MANIFEST.MF文件中定义所有自定义配置。 配置maven-jar-plugin以使用您的MANIFEST.MF文件,并使用任何Maven定制对其进行扩充。

    例如,考虑一个包含Java代理的JAR文件。 为了运行Java代理,它需要定义Premain-Class和权限。 清单3显示了这样的MANIFEST.MF文件的内容:

    清单3.自定义MANIFEST.MF文件中的Premain-Class定义
    Manifest-Version: 1.0 Premain-Class: com.geekcap.openapm.jvm.agent.Agent Can-Redefine-Classes: true Can-Retransform-Classes: true Can-Set-Native-Method-Prefix: true

    在清单3中 ,我指定了Premain-Class com.geekcap.openapm.jvm.agent.Agent将被授予重新定义和重新转换类的权限。 接下来,我更新maven-jar-plugin以包括MANIFEST.MF文件,如清单4所示:

    清单4.包括Premain-Class
    <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifestFile> src/main/resources/META-INF/MANIFEST.MF </manifestFile> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass> com.geekcap.openapm.ui.PerformanceAnalyzer </mainClass> </manifest> </archive> </configuration> </plugin>
    Maven的3

    Maven 2已成为最受欢迎和使用最广泛的开源Java生命周期管理工具之一。 Maven 3于2010年9月晋升为alpha 5,为Maven带来了一些期待已久的变化。 请参阅“ 相关主题”部分,以了解Maven 3的新增功能。

    这是一个有趣的示例,因为它都定义了一个Premain-Class ,它允许JAR文件作为Java代理工作,并且具有mainClass ,使它可以作为可执行JAR文件运行。 在这个特定示例中,我使用了OpenAPM (我构建的代码跟踪工具)来定义将由Java代理和用户界面记录的代码跟踪,这将有助于对记录的跟踪进行分析。 简而言之,该示例显示了将显式清单文件与动态修改相结合的强大功能。

    3.依赖树

    Maven最有用的功能之一是它对依赖项管理的支持:您只需定义应用程序所依赖的库,然后Maven即可找到它们(在本地或中央存储库中),下载它们并使用它们来编译代码。 。

    有时,您可能需要了解特定依赖项的来源-例如,如果要在构建中找到同一JAR文件的不同且不兼容的版本。 在这种情况下,您需要阻止将一个版本的JAR文件包含在您的构建中,但是首先您需要找到保存JAR的依赖项。

    一旦您知道以下命令,查找依赖关系就变得异常容易:

    mvn dependency:tree

    dependency:tree参数显示所有直接依赖关系,然后显示所有子依赖关系(及其子依赖关系,依此类推)。 例如,清单5是我的一个依赖项所要求的客户端库的摘录:

    清单5.一个Maven依赖树
    [INFO] ------------------------------------------------------------------------ [INFO] Building Client library for communicating with the LDE [INFO] task-segment: [dependency:tree] [INFO] ------------------------------------------------------------------------ [INFO] [dependency:tree {execution: default-cli}] [INFO] com.lmt.pos:sis-client:jar:2.1.14 [INFO] +- org.codehaus.woodstox:woodstox-core-lgpl:jar:4.0.7:compile [INFO] | \- org.codehaus.woodstox:stax2-api:jar:3.0.1:compile [INFO] +- org.easymock:easymockclassextension:jar:2.5.2:test [INFO] | +- cglib:cglib-nodep:jar:2.2:test [INFO] | \- org.objenesis:objenesis:jar:1.2:test

    您可以在清单5中看到sis-client项目需要woodstox-core-lgpl和easymockclassextension库。 easymockclassextension库又需要cglib-nodep库和objenesis库。 如果我在使用objenesis遇到问题,例如1.2和1.3两个版本,则此依赖关系树将向我显示1.2工件是由easymockclassextension库间接导入的。

    dependency:tree参数为我节省了许多调试损坏的构建的时间; 希望对您也一样。

    4.针对不同环境的构建

    大多数实质性项目至少具有一组核心环境,其中包括与开发,质量保证(QA),集成和生产相关的任务。 管理所有这些环境的挑战在于配置构建,该构建必须连接到正确的数据库,执行正确的脚本集并将所有正确的工件部署到每个环境。 使用Maven配置文件可让您执行所有这些操作,而不必分别为每个环境构建明确的说明。

    关键在于将环境配置文件与面向任务的配置文件相结合。 每个环境概要文件都定义了其特定的位置,脚本和服务器。 因此,在我的pom.xml文件中,我将定义面向任务的构建,如清单6所示:

    清单6.部署构建
    <build> <plugins> <plugin> <groupId>net.fpic</groupId> <artifactId>tomcat-deployer-plugin</artifactId> <version>1.0-SNAPSHOT</version> <executions> <execution> <id>pos</id> <phase>install</phase> <goals> <goal>deploy</goal> </goals> <configuration> <host>${deploymentManagerRestHost}</host> <port>${deploymentManagerRestPort}</port> <username>${deploymentManagerRestUsername}</username> <password>${deploymentManagerRestPassword}</password> <artifactSource> address/target/addressservice.war </artifactSource> </configuration> </execution> </executions> </plugin> </plugins> </build>

    此构建执行tomcat-deployer-plugin ,该tomcat-deployer-plugin配置为连接到特定的主机,端口以及特定的用户名和密码凭据。 所有这些信息都是使用变量定义的,例如${deploymentmanagerRestHost} 。 这些变量是在每个配置文件中按环境定义的,如清单7所示:

    清单7.环境配置文件
    <profiles> <profile> <id>dev</id> <properties> <deploymentManagerRestHost>10.50.50.52</deploymentManagerRestHost> <deploymentManagerRestPort>58090</deploymentManagerRestPort> <deploymentManagerRestUsername>myusername</deploymentManagerRestUsername> <deploymentManagerRestPassword>mypassword</deploymentManagerRestPassword> </properties> </profile> <profile> <id>qa</id> <properties> <deploymentManagerRestHost>10.50.50.50</deploymentManagerRestHost> <deploymentManagerRestPort>58090</deploymentManagerRestPort> <deploymentManagerRestUsername>myotherusername</deploymentManagerRestUsername> <deploymentManagerRestPassword>myotherpassword</deploymentManagerRestPassword> </properties> </profile> </profiles>

    部署Maven配置文件

    在清单7的概要文件中,我定义了两个概要文件,并根据概要文件名称中的值激活了它们。 如果选择的概要文件是dev那么将使用开发部署信息。 如果选择的概要文件是qa ,那么将使用QA部署信息,依此类推。

    这是部署到开发的命令:

    mvn -Pdev clean install

    –Pdev标志告诉Maven激活开发配置,而传递-Pqa将激活QA配置。

    5.自定义Maven插件

    Maven提供了数十种预建插件供您使用,但是在某些时候,您可能会发现自己需要自定义插件。 构建自定义Maven插件非常简单:

    创建一个新项目,将POM包装设置为“ maven-plugin 。 包括对maven-plugin-plugin的调用,该调用定义了您公开的插件目标。 创建一个Maven插件“ mojo ”类(扩展AbstractMojo的类)。 注释该类以定义将作为配置参数公开的目标和变量。 注释@Mojo是必需的,它控制执行mojo的方式和时间。 实现execute()方法,当您的插件被调用时将被调用。

    作为示例,清单8显示了用于部署Tomcat的自定义插件的相关部分:

    清单8. TomcatDeployerMojo.java
    package net.fpic.maven.plugins; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; /** * Goal that deploys a web application to Tomcat */ @Mojo(name = "deploy", defaultPhase = LifecyclePhase.INSTALL) public class TomcatDeployerMojo extends AbstractMojo { /** * The host name or IP address of the deployment server */ @Parameter(alias = "host", property = "deploy.host", required = true) private String serverHost; /** * The port of the deployment server */ @Parameter(alias = "port", property = "deploy.port", defaultValue = "58020", required = true) private String serverPort; /** * The username to connect to the deployment manager (if omitted then the plugin * attempts to deploy the application to the server without credentials) */ @Parameter(alias = "username", property = "deploy.username") private String username; /** * The password for the specified username */ @Parameter(alias = "password", property = "deploy.password") private String password; /** * The name of the source artifact to deploy, such as target/pos.war */ @Parameter(alias = "artifactSource", property = "deploy.artifactSource", required = true) private String artifactSource; /** * The destination name of the artifact to deploy, such as ROOT.war. * If not present then the * artifact source name is used (without pathing information) */ @Parameter(alias = "artifactDestination", property = "deploy.artifactDestination") private String artifactDestination; public void execute() throws MojoExecutionException { getLog().info("Server Host: " + serverHost + ", Server Port: " + serverPort + ", Artifact Source: " + artifactSource + ", Artifact Destination: " + artifactDestination); // Validate our fields if (serverHost == null) { throw new MojoExecutionException( "No deployment host specified, deployment is not possible"); } if (artifactSource == null) { throw new MojoExecutionException( "No source artifact is specified, deployment is not possible"); } ... } }

    在类级别, @Mojo批注值name指定此MOJO执行的目标,而lifecyclePhase指定目标执行的阶段。 除了映射到包含实际值的系统属性的表达式之外,每个公开的属性都有一个@Parameter批注,该批注指定将通过其执行参数的别名。 如果属性设置了required=true ,那么它是必需的。 如果它具有defaultValue ,那么如果未指定该值,则将使用该值。 在execute()方法中,可以调用getLog()来访问Maven记录器,该记录器将根据记录级别将指定的消息输出到标准输出设备。 如果该插件失败,则抛出MojoExecutionException将导致构建失败。

    结论

    您可以仅将Maven用于构建,但最好的Maven是项目生命周期管理工具。 本文介绍了五个鲜为人知的功能,这些功能可以帮助您更有效地使用Maven。 请参阅“ 相关主题”部分,以了解有关Maven的更多信息。


    翻译自: https://www.ibm.com/developerworks/java/library/j-5things13/index.html

    相关资源:阿帕奇maven3.3.3
    Processed: 0.009, SQL: 9