【问题标题】:How do I put all required JAR files in a library folder inside the final JAR file with Maven?如何使用 Maven 将所有必需的 JAR 文件放在最终 JAR 文件内的库文件夹中?
【发布时间】:2012-07-30 07:27:17
【问题描述】:

我在我的独立应用程序中使用 Maven,我想将我的 JAR 文件中的所有依赖项打包到一个库文件夹中,如此处的答案之一所述:

How can I create an executable JAR with dependencies using Maven?

我希望我的最终 JAR 文件有一个库文件夹,其中包含作为 JAR 文件的依赖项,而不像 maven-shade-plugin 那样将依赖项以文件夹的形式放置,如 .m2 文件夹中的 Maven 层次结构。

嗯,实际上当前配置可以满足我的需求,但是在运行应用程序时加载 JAR 文件时遇到问题。我无法加载类。

这是我的配置:

<plugins>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>false</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

该项目在 Eclipse 中运行良好,并且 JAR 文件按我的意愿放置在我的最终 JAR 文件内的库文件夹中,但是当从目标文件夹运行最终 JAR 文件时,我总是得到ClassNotFoundException

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.myapp.MainClass. Program will exit.

如何解决这个异常?

【问题讨论】:

  • 您使用哪个命令来运行 jar?也许你可能更喜欢 maven exec 插件?
  • 异常信息与POM文件相比是否过时?似乎正在搜索主类 com.myapp.MainClass,而不是 com.tastycafe.MainClass
  • @Duncan Jones,复制粘贴问题,我编辑了问题
  • 注意,如果你想要jar里面的jar,那么Java中的标准类加载器无法理解它们。
  • 如何使其将maven依赖项放在lib文件夹中但在JAR之外?

标签: java maven jar build-process classloader


【解决方案1】:

以下是我的解决方案。测试它是否适合您:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- <classpathPrefix>lib</classpathPrefix> -->
                <!-- <mainClass>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

第一个插件将所有依赖项放在target/classes/lib文件夹中,第二个插件将library文件夹包含在最终的JAR文件中,并配置Manifest.mf文件。

但是您需要添加自定义类加载代码来加载 JAR 文件。

或者,为了避免自定义类加载,您可以使用“${project.build.directory}/lib,但在这种情况下,您在最终 JAR 文件中没有依赖项,这违背了目的。

问这个问题已经两年了。尽管如此,嵌套 JAR 文件的问题仍然存在。我希望它可以帮助某人。

【讨论】:

  • 用法:mvn install, cd target, java -jar MyJarFile-1.0.jar
  • 我错过了什么?这将创建一个清单类路径条目,其中包含“lib/”和 lib 文件夹中的所有单个 jar。这是故意的吗?为什么?
  • 在我将 "${project.build.directory}/classes/lib" 更改为 ${project.build.directory}/lib 后它工作了
  • 不幸的是包含声明为提供的依赖项。
【解决方案2】:

更新:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 

【讨论】:

  • 这会将 lib 文件夹放在 jar 之外(这不是我想要的)。这比将 lib 放入 jar 更好吗?在这种情况下如何将应用程序交付给客户端?
  • 现在对我来说更清楚了。让我做一个谷歌搜索。但我想知道为什么要复制可执行 jar 文件内指定文件夹中的所有依赖 jar 文件。如果所有的依赖jar文件都在jar文件里面,为什么还要放在lib文件夹下呢?
【解决方案3】:

最简单最有效的方法是使用这样的超级插件:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${project.artifactId}-${project.version}</finalName>
            </configuration>
        </plugin>

您将在一个 JAR 文件中对所有内容进行反规范化。

【讨论】:

  • 除了我当前的配置之外还要使用它吗?这个插件到底是做什么的?
  • 我不希望我的 jar 文件看起来像这样,我希望像 netbean 一样将所有依赖项放在 jar 文件内的 lib 文件夹中。
  • 这对我有用,但它会产生一个巨大的 jar 文件。我尝试移植的 ant 文件会生成一个 495K 的 jar,这会生成一个 18M 的文件。
【解决方案4】:

executable packer maven plugin 可用于该目的:创建包含所有依赖项的独立 Java 应用程序,作为特定文件夹中的 JAR 文件。

只需将以下内容添加到&lt;build&gt;&lt;plugins&gt; 部分内的pom.xml(请务必相应地替换mainClass 的值):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

运行mvn package 后,构建的JAR 文件位于target/&lt;YourProjectAndVersion&gt;-pkg.jar。它的所有编译时和运行时依赖项都将包含在 JAR 文件内的 lib/ 文件夹中。

免责声明:我是插件的作者。

【讨论】:

  • 我试过了,我可以说它正在工作......正如你所说,这个插件创建一个jar文件,它的库(jars)进入jar中的一个lib目录......配置是真的很容易.. 我认为这是这个问题的作者所期望的 ...我会给你我的投票...我发现的唯一缺点(这就是为什么我无法使用它),当我执行我的 jar 并显示应用程序时有延迟(大约 20 秒)可能是因为在自定义类加载器中注册库的过程......但这是一个很好的方法和一个优秀的插件...
  • 我绝不是 maven 专家,但我按照 GitHub 页面上的说明进行操作,但它不起作用。并且不起作用,我的意思是 maven 甚至不承认它在 pom 文件中。我一无所知。
【解决方案5】:

点击此链接:

How To: Eclipse Maven install build jar with dependencies

我发现这不是可行的解决方案,因为类加载器不会从 jar 中加载 jar,所以我认为我将解压缩 jar 中的依赖项。

【讨论】:

    【解决方案6】:

    我是这样做的:

        <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <appendAssemblyId>false</appendAssemblyId>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>com.project.MainClass</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
    

    然后我就跑了:

    mvn assembly:assembly
    

    【讨论】:

    • 请注意,您应该始终事先进行编译,因为assembly 只会将“目标/类”中的任何内容放入 JAR 中。这将确保 JAR 包含您最近对源代码所做的任何更改。所以,你应该这样做:mvn clean compile assembly:assembly.
    【解决方案7】:

    我找到了这个问题的答案:

    http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

    您不仅可以在 lib 文件夹中获得依赖的 lib 文件,还可以获得包含 unix 和 dos 可执行文件的 bin 目录。

    可执行文件最终使用 -cp 参数调用 java,该参数也列出了所有依赖库。

    全部位于目标文件夹内的 appasembly 文件夹中。史诗。

    ============== 是的,我知道这是一个旧线程,但它在搜索结果中仍然很高,所以我认为它可能会对像我这样的人有所帮助。

    【讨论】:

      【解决方案8】:

      这显然是一个类路径问题。考虑到当您在 IDE 之外运行程序时,类路径必须稍作更改。这是因为 IDE 会加载相对于项目根文件夹的其他 JAR,而对于最终 JAR,这通常不是真的。

      在这些情况下,我喜欢手动构建 JAR。我最多只需要 5 分钟,它总能解决问题。我不建议你这样做。找到一种使用 Maven 的方法,这就是它的目的。

      【讨论】:

      • @SoboLAN 手动构建 JAR 不是这里的解决方案。意图是使用Maven,这与“手动”完全相反!
      • @DuncanJones 你完全正确。我确实建议他使用 Maven 来做这件事。但是,我没有这方面的经验,也不知道要推荐什么解决方案。我编辑了我的答案以反映这一点。
      猜你喜欢
      • 2012-04-19
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 2013-10-08
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多