【问题标题】:Is there a Maven plugin that runs a non-fat jar?是否有运行非胖 jar 的 Maven 插件?
【发布时间】:2015-11-06 18:12:07
【问题描述】:

想象一个普通的 java maven 项目,它有一个 Main 类来生成工件 project-a.jar。该项目依赖于project-b.jar。

是否有 Maven 插件允许通过这样的命令运行该 jar?

mvn run-plugin:run org.mygroup:project-a:3.1 <args>

插件将解析运行时依赖项(使用 META-INF/maven/(...)/pom.xml),将项目及其依赖项安装到本地 maven 存储库(如果还没有),构建类路径并调用

java -cp (...)/project-a-3.1.jar;(...)/project-b-2.1.jar org.mygroup.Main <args>

我知道通常的方法是构建一个包含依赖项的可执行(胖)jar,但这不是我想要的。

实际上,甚至不需要从 jar 中读取 pom,因为 maven 可以从给定坐标的存储库中下载它。

为什么这个问题与Maven Run Project 问题不同:

我不想从已经签出项目的源代码开始。 所以通常使用 exec 插件是不适用的。 Maven Run Project 问题的 OP 显然假设存在源代码项目文件夹。她的目的是测试,她接受了一个显然需要一个项目的答案。这两个问题的措辞也是正确的。 “project”和“jar”这两个词是有区别的,它们在各自上下文中的实际含义也大不相同。

【问题讨论】:

  • 我认为您正在寻找 maven exec 插件,请参阅可能的重复项:Maven Run Project
  • META-INF/maven/(...)/pom.xml 结构不保证存在。当您将maven-jar-pluginaddMavenDescriptor 配置为false 时,就会出现这种情况。
  • 不,我认为该问题以及 exec 插件都要求您已经在该项目中(已从包含 pom 的源代码文件夹中签出源代码并执行 maven)。跨度>
  • 您应该告诉我们您的大局是什么,如果您不想使用源代码树,那么我认为 maven 不是您需要的工具。您可能应该使用 MANIFEST.MF 指定 deps(请参阅此answer
  • 已经有一些插件不需要源代码树,最明显的一个就是原型插件。

标签: java maven maven-plugin


【解决方案1】:

您可以使用appassembler-maven-plugin 插件,它会为您创建一个在类路径中具有依赖项的shell 脚本。这是一个示例配置

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>appassembler-maven-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>assemble</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <extraJvmArguments>-Xms256m -Xmx1536m</extraJvmArguments>
                <programs>
                    <program>
                        <mainClass>com.package.MyMainClass</mainClass>
                        <name>TestFormattingUtils</name>
                    </program>
                </programs>
            </configuration>
        </plugin>

您可以在.../target/appassembler/bin 中找到输出脚本。您可以手动检查脚本,您会看到它正在执行您想要的命令类型,它通过命令行将 jars 添加到类路径中。即java -jar (...)/project-a-3.1.jar -cp (...)/project-b-2.1.jar &lt;args&gt;

【讨论】:

  • 使用 shell 是脚本不是一种选择,因为它也必须在 Windows 上工作。
  • 它还输出一个窗口,我只是从不看它。同名,但以 .bat 结尾。
  • 听起来很有趣,我会看看它,但是当 java 和 maven 已经可用时,使用脚本(和不同的脚本)有点脆弱并且不是很优雅。
  • 我知道你的意思。您可以通过首先调用插件、生成新脚本然后立即运行它来运行它。我不会对脚本或类似的东西进行版本控制。 (否则它会很脆)
【解决方案2】:

我也不喜欢 jars-in-jar,但我确实维护了各种具有很多依赖项的工具。因此,有一次,我决定编写一个可执行的AppBoot jar,它将 lib 子目录中的所有 jar 放入类加载器中,然后调用所需(可执行)jar 的 main-method。这个问题促使我调查exec-maven-plugin 是否可以做类似的事情,并且可以。

exec-maven-plugin 不需要“Java 项目”目录,但需要目录中的pom.xml。我使用的pom.xml 如下所示,注意它可以放在任何(空)目录中,并且可以通过在该目录中打开shell/prompt 并执行mvn exec:exec 来启动应用程序。使用mvn -X exec:exec 查看exec-maven-plugin 使用的类路径。

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.descartes</groupId>
    <artifactId>exec-embed-demo</artifactId>
    <version>1.2.2-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!-- Start the demo using Maven repository artifacts, execute with "mvn exec:exec" -->

    <properties>
        <demo.version>1.2.1.GH</demo.version>
        <mainclass>com.descartes.basicjsp.embed.demo.Launch</mainclass>
        <appname>${project.artifactId}</appname>
        <homedir>${project.basedir}/</homedir>
    </properties>

    <dependencies>
        <dependency>
            <!-- exec-maven-plugin will get all required (runtime) jar-files from this dependency. -->
            <groupId>com.descartes</groupId>
            <artifactId>basic-jsp-embed-demo</artifactId>
            <version>${demo.version}</version>
        </dependency>
    </dependencies>

    <build>
        <!-- The "outputDirectory" is added to the classpath by the exec-maven-plugin. -->
        <!-- Add this pom's directory to the classpath instead of "./target/classes". -->
        <!-- The directory should contain "logback.xml" to prevent a million lines of debug output from Tomcat. -->
        <outputDirectory>${homedir}</outputDirectory>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.4.0</version>
                <!-- mvn exec:exec configuration -->
                <!-- Embedded Tomcat will not stop with "ctrl-c" -->
                <!-- Use http://localhost:8080/shutdown instead -->
                <configuration>
                    <executable>java</executable>
                    <arguments>
                        <argument>-Dapp.name=${appname}</argument>
                        <argument>-Dapp.home.dir=${homedir}</argument>
                        <argument>-Dapp.conf.dir=${homedir}</argument>
                        <argument>-cp</argument>
                        <classpath/>
                        <argument>${mainclass}</argument>
                    </arguments>
                </configuration>
                <!-- mvn exec:java configuration -->
                <!-- "ctrl-c" stops Tomcat but embedded Tomcat fails to start properly, probably a classloader issue. -->
                <!--
                <configuration>
                    <mainClass>${mainclass}</mainClass>
                    <systemProperties>
                        <systemProperty>
                            <key>app.name</key>
                            <value>${appname}</value>
                        </systemProperty>
                        <systemProperty>
                            <key>app.home.dir</key>
                            <value>${homedir}/</value>
                        </systemProperty>
                        <systemProperty>
                            <key>app.conf.dir</key>
                            <value>${homedir}/</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
                -->
            </plugin>
        </plugins>
    </build>

</project>

AppBoot 是使用嵌入式 Tomcat 的 basic-jsp-embed 项目的一部分,该项目可以在 here 找到(要安装,下载最新版本,解压缩 zip 文件并在根目录中运行“mvn install”多模块项目的目录)。

附带说明:管理 jar 集很棘手,请使用 jHades 之类的工具来验证在不同 jar 文件中使用同一类的多个版本时不会遇到问题。

【讨论】:

  • 这不是我要找的东西,但感谢您提供有用的信息!
【解决方案3】:

您正在寻找maven exec plugin

mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"]

会运行你的程序

【讨论】:

  • 我认为这不能回答 OP 问题。此命令需要在项目源上运行,不是最终的 jar。
  • 我看不到您在命令中指定要执行的项目坐标的位置。你如何指定它?通过从项目文件夹执行...但这不是问题。
  • maven-exec-plugin 运行编译后的/target/classes/**,而不是最终的工件。而且在当前版本 1.6.0 中,它不能同时运行提供的依赖项和运行时依赖项。
【解决方案4】:

Maven不能做你想做的事,只是因为一旦它被构建到一个最终的jar中,它就无法解析project A的依赖关系。

Maven 不会神奇地从 Internet 下载库:它的工作原理是 repositoriespom.xml 中的定义。如果没有pom.xml,就像您似乎建议的那样,它怎么知道从哪里下载库? Maven 不是一个下载工具,它是一个项目管理工具,你拥有的不再是一个项目,而是一个最终的库。

由于您可以控制 project A,因此您应该真正依赖 Maven 约定并构建一个 fat jar 或一个程序集(使用 maven-assembly-plugin)。

顺便说一句,位于META-INF 下的pom.xml 文件不能保证存在,事实上,如果您查看Spring 工件,它并不存在。看看Maven Archiver documentation:这个pom 文件的存在是由addMavenDescriptor 布尔属性控制的。将此属性设置为false,您的主工件将没有此pom 文件。

【讨论】:

  • 见我上面的评论。我控制 project-a,因此可以保证它包含 pom。 Maven 不需要更多的 pom 来加载依赖项。
  • 是的,但是因为不能保证,所以没有插件可以做你想做的...
  • 你知道所有的maven插件吗?
猜你喜欢
  • 2017-02-13
  • 2018-12-14
  • 1970-01-01
  • 2018-07-15
  • 1970-01-01
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
相关资源
最近更新 更多