如何使用Maven将所有必需的JAR文件放入最终JAR文件中的库文件夹中?


104

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

如何使用Maven创建具有依赖项的可执行JAR?

我希望最终的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.

如何解决此异常?


1
您使用哪个命令来运行jar?也许您可能更喜欢maven exec插件?
安德烈·鲍里索夫

与POM文件相比,异常消息是否已过期?似乎com.myapp.MainClass正在搜索主类,而不是com.tastycafe.MainClass
邓肯·琼斯

@邓肯·琼斯(Duncan Jones),复制粘贴问题,我编辑了问题
Mahmoud Saleh

3
请注意,如果要将jar放在jar中,则Java中的标准类加载器无法理解它们。
托尔比约恩Ravn的安徒生

如何使其将Maven依赖项放在lib文件夹中但在JAR之外?
ed22 '18年

Answers:


81

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

<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文件夹中,第二个插件将库文件夹包含在最终的JAR文件中,并配置Manifest.mf文件。

但是随后您将需要添加自定义类加载代码以加载JAR文件。

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

提出问题已经两年了。但是,嵌套JAR文件的问题仍然存在。希望对您有所帮助。


1
用法:mvn安装,cd目标,java -jar MyJarFile-1.0.jar
djb

我想念什么?这将创建一个清单类路径条目,其中包含“ lib /”和lib文件夹中的所有单个jar。这是故意的吗?为什么?
gapvision '16

2
在我将“ $ {project.build.directory} / classes / lib”更改为$ {project.build.directory} / lib之后,它起作用了
Rajendra Thorat 2016年

1
不幸地包括声明为提供的依赖项。
Philippe Gioseffi

@Rajendra谢谢,这对您有所帮助:$ {project.build.directory} / lib
Mindaugas

30

更新:

<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> 

4
这将lib文件夹放在jar之外(这不是我想要的)。这比将lib放入罐中更好吗?以及在这种情况下如何将应用程序交付给客户端?
Mahmoud Saleh 2012年

现在对我来说更清楚了。让我做一个谷歌搜索。但是我想知道为什么要在可执行jar文件内的指定文件夹中复制所有依赖项jar文件。如果所有依赖项jar文件都在jar文件中,那么为什么需要在lib文件夹中找到它们?
艾哈迈德(Ahmet Karakaya)

23

最简单,最有效的方法是使用uber插件,如下所示:

          <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-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

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


除了我当前的配置,还使用它吗?这个插件到底做什么?
Mahmoud Saleh 2012年

15
我不希望我的jar文件看起来像这样,我想像netbean一样将所有依赖项放在jar文件中的lib文件夹中。
Mahmoud Saleh 2012年

12

可执行打包机Maven插件可以用来正是出于这个目的:创建包含特定文件夹中的所有依赖关系的JAR文件独立的Java应用程序。

只需将以下内容添加到pom.xml<build><plugins>部分的内部即可(请确保相应地替换相应的值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>

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

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


我试过了,我可以说它正在工作...正如您所说,此插件创建了一个jar文件,并将其库(jar)放入jar的lib目录中。配置确实很简单.. 我认为这就是这个问题的作者期望 ...我将投票给我...我发现它的唯一缺点(这就是为什么我不能使用它的原因),执行我的方法会有延迟jar和应用程序的显示(大约20秒),可能是由于在自定义类加载器中注册库的过程……但这是一个很好的方法,也是一个出色的插件……
Adam M. Gamboa G.


3

这是我的方法:

    <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

1
请注意,您应该始终事先进行编译,因为这只assembly会将JAR中“目标/类”中的内容放入。这将确保JAR包括您最近对源代码所做的任何更改。因此,您应该执行以下操作:mvn clean compile assembly:assembly
naXa 2014年

2

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

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

您不仅可以在lib文件夹中获取依赖的lib文件,而且还可以同时获得带有unix和dos可执行文件的bin目录。

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

整个批次位于目标文件夹内的appasembly文件夹中。史诗。

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


1

这显然是类路径问题。请注意,在IDE外部运行程序时,类路径必须有所变化。这是因为IDE会加载相对于项目根文件夹的其他JAR,而对于最终的JAR,通常不是这样。

在这种情况下,我想做的是手动构建JAR。我最多只需要5分钟,就可以解决问题。我不建议您这样做。找到使用Maven的方法,这就是它的目的。


@SoboLAN此处无法手动构建JAR。目的是使用Maven,它与“手册”完全相反!
邓肯·琼斯

@DuncanJones你完全正确。我确实建议他使用Maven来做到这一点。但是,我没有经验,也不知道确切推荐什么解决方案。我修改了答案以反映这一点。
Radu Murzea
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.