在Java类路径的目录中包含所有jar


1018

有没有办法将所有jar文件包含在类路径的目录中?

我正在尝试java -classpath lib/*.jar:. my.package.Program,但找不到这些jar中肯定存在的类文件。我是否需要将每个jar文件分别添加到类路径?


3
抱歉,我从未接受过。它应该是社区Wiki。从未使用提供的答案之一。我相信我创建了一个shell脚本,该脚本只扫描了lib /目录,并通过解析文件名创建了类路径。
克里斯·塞拉

此Java新功能中存在某种错误,因为它无法按所述方式工作。如答案之一所述,我放弃并使用了Ant来解决它。
Alex R


1
Windows中的通配符处理存在问题。 stackoverflow.com/questions/11607873/...
Mykhaylo Adamovych

6
简短的答案:(1)放下该.jar部件,(2)必须至少有2个部件,;在Windows上通常用:别的符号隔开。例如:java -classpath ".;lib/*" Program
Evgeni Sergeev 2014年

Answers:


1159

使用Java 6或更高版本,classpath选项支持通配符。请注意以下几点:

  • 使用双引号("
  • 使用*,不*.jar

视窗

java -cp "Test.jar;lib/*" my.package.MainClass

的Unix

java -cp "Test.jar:lib/*" my.package.MainClass

这类似于Windows,但使用:代替;。如果不能使用通配符,则bash允许使用以下语法(其中lib包含所有Java归档文件的目录):

java -cp $(echo lib/*.jar | tr ' ' ':')

(请注意,使用类路径与该-jar选项不兼容。另请参见:在命令提示符下执行具有多个类路径库的jar文件

了解通配符

类路径文档中:

类路径条目可以包含基本名称通配符*,该通配符被认为等效于指定扩展名为.jar或的目录中所有文件的列表.JAR。例如,类路径条目foo/*指定名为foo的目录中的所有JAR文件。一个类路径条目,仅由组成,*扩展为当前目录中所有jar文件的列表。

包含的类路径条目*将不匹配类文件。要在单个目录foo中匹配类和JAR文件,请使用 foo;foo/*foo/*;foo。选择的顺序确定是否在中的类和资源先于foo中的JAR文件加载foo,反之亦然。

子目录不是递归搜索的。例如,foo/*验看JAR文件只有在foo,不foo/barfoo/baz等等。

在扩展的类路径中枚举目录中JAR文件的顺序未指定,并且可能因平台而异,甚至在同一台计算机上有时也有所不同。结构良好的应用程序不应依赖于任何特定顺序。如果需要特定顺序,则可以在类路径中显式枚举JAR文件。

通配符的扩展在类加载过程本身的早期(而不是在程序的主要方法被调用之前)进行。输入类路径中包含通配符的每个元素都将由(可能为空)元素序列替换,这些元素序列是通过枚举命名目录中的JAR文件而生成的。例如,如果目录foo包含a.jarb.jarc.jar,则将类路径foo/*扩展为foo/a.jar;foo/b.jar;foo/c.jar,并且该字符串将是system属性的值 java.class.path

CLASSPATH环境变量未从处理过的任何不同的-classpath(或-cp)的命令行选项。也就是说,在所有这些情况下都应使用通配符。但是,Class-Path jar-manifest标头中不接受类路径通配符。

注意:由于Java 8中的一个已知错误,Windows示例必须在前面的条目中使用反斜杠,并在其后加上星号:https : //bugs.openjdk.java.net/browse/JDK-8131329


2
该功能的文档记录很少,并且似乎需要满足一些不太明显的前提条件才能正常工作。
Alex R

1
+1为最后一个bash / tr技巧。这里的Java / JamVM不喜欢工作目录之外路径的通配符,而是使用shell通配符+ trworks 显式引用每个JAR !
SUPR

1
我有一个java -classpath /jars/*:/anotherJarsDir/* com.test.MyClass没有引号的命令,它工作正常。我想知道为什么shell无法扩展它并出错?
yellavon 2014年

3
也不要使用~在-cp
苏海尔硅

1
您的Windows示例不适用于Java 8或更早版本,但可以使用以下类路径:Test.jar; lib \ * ...正斜杠是可以的,除非在星号和其他几个斜杠之前...请参见bugs.openjdk。 java.net/browse/JDK-8131329
philwalk

226

在Windows下可以正常工作:

java -cp "Test.jar;lib/*" my.package.MainClass

这不起作用:

java -cp "Test.jar;lib/*.jar" my.package.MainClass

注意* .jar,因此*通配符应单独使用


在Linux上,以下工作:

java -cp "Test.jar:lib/*" my.package.MainClass

分隔符是冒号而不是分号。


17
完美的答案。请注意2件重要的事情:1)使用引号,2)仅使用*,而不是* .jar
Wim Deblauwe 2012年

4
一年零八个月后,我对包含UNIX版本的修改再次为我节省了时间。:)好笑的是,它无法识别*.jar只有我的jar文件*
jmort253

我发现类路径的顺序很重要(但我不知道为什么)。在切换类路径顺序之前,我一直遇到错误。
user13107 2014年

@ jmort253,问题是,这不是外壳*扩展,而是通配符是java解析类路径,看到*并填充了通配符
塞巴斯蒂安

1
@SebastianGodelet-是的,这就是正则表达式通配符和这种表示法之间让我感到困惑的地方,我想这不一样​​。通常,让我省钱的是知道:一个平台与另一个平台之间的区别;。:)我大约每年从命令行使用Java进行一次编译,只是不记得有多少次令人讨厌。
jmort253 2014年

67

通过部署一个 jar文件myapp.jar来解决此问题,该文件包含一个manifestManifest.mf)文件,该文件指定了带有其他所需jar的类路径,然后将其与该jar一起部署。在这种情况下,只需要java -jar myapp.jar在运行代码时声明即可。

因此,如果将main部署jar到某个目录中,然后将相关的jar放入该lib目录下的文件夹中,则清单如下所示:

Manifest-Version: 1.0
Implementation-Title: myapp
Implementation-Version: 1.0.1
Class-Path: lib/dep1.jar lib/dep2.jar

注意:这与平台无关-我们可以使用相同的jar在UNIX服务器或Windows PC上启动。


这似乎对很多人都有效,但是Java似乎完全忽略了清单文件中的Class-Path条目。如果不使用-cp手动将“ lib / *”添加到类路径中,则无法运行该应用程序。有任何想法吗?
Raku,

6
oxbow_lakes的答案并不完全正确;如果您使用java -jar myapp.jar启动该jar,则将尊重Class-Path的事情(并且仅能兑现; -cp / -classpath会被忽略!)。我认为oxbow_lakes是在他编写“ java -classpath myapp.jar”时写的。
rzwitserloot 2013年

47

我在使用java-sun 1.6.0_24的Ubuntu 10.04上的解决方案在“ lib”目录中具有所有jar:

java -cp。:lib / * my.main.Class

如果失败,则以下命令应该起作用(将lib目录中的所有* .jars打印到classpath参数中)

java -cp $(对于lib / *。jar中的i;执行echo -n $ i:;完成)。my.main.Class

4
一个有趣的笔记。java -cp lib / * my.main.Class总是会失败,因为lib / *的shell glob扩展,而java -cp。:lib / * my.main.Class不会因为。:lib / *不是有效的glob而失败路径。花点时间注意一下
albfan 2012年

1
这行不通;linux将扩展。您可以尝试:java -cp'。:lib / ',并且效果很好(请注意单引号!双引号将不起作用!)。实际上,。:lib / *如果不是由于冒号而引起的合法问题,则可能会起作用,但是感觉有些。我要加上引号。单引号指示bash请勿触摸内容的任何部分。
rzwitserloot

(在这种情况下)使用单引号还是双引号都没有关系。您要防止外壳扩展(使)*膨胀(仅此而已)。并将文本“ lib / *”随意传递给JVM,以便VM将其识别为“特殊模式”,并自行搜索jar文件。
Angel O'Sphere

36

简短答案: java -classpath lib/*:. my.package.Program

Oracle在标题为“ 理解类路径通配符”的部分下为Java 6Java 7提供了有关在类路径中使用通配符的文档。(在撰写本文时,这两个页面包含相同的信息。)以下是重点摘要:

  • 通常,要在给定目录中包含所有JAR,可以使用通配符*not *.jar)。

  • 通配符仅匹配JAR,而不匹配类文件。要获得目录中的所有类,只需将classpath条目以目录名结尾。

  • 可以将以上两个选项组合在一起,以将所有JAR文件和类文件包含在目录中,并且适用通常的类路径优先级规则。例如-cp /classes;/jars/*

  • 通配符将不会在子目录中搜索JAR。

  • 如果使用CLASSPATHsystem属性或-cpor -classpath命令行标志,则上述要点是正确的。但是,如果您使用Class-PathJAR清单标头(就像您对ant构建文件所做的那样),将接受通配符。

是的,我的第一个链接与得分最高的答案(我没有希望超越)中提供的链接相同,但是该答案在链接之外没有提供太多解释。因为那种行为是不鼓励对堆栈溢出,这些天,我想我就可以扩大。


我的问题是lib / *。jar而不是lib / *。非常感谢,此问题已解决。我注意到:和;之间有区别。但这可能是我在同一时间测试很多更改。
Eyad Ebrahim 2012年

感谢您强调*和* .jar之间的差异
burakhan alkan,

36

Windows

 java -cp file.jar;dir/* my.app.ClassName

Linux

 java -cp file.jar:dir/* my.app.ClassName

提醒:
- 的Windows路径分隔符是;
- Linux的路径分隔符是:
-在Windows中,如果CP参数不包含空格,在“报价”是可选


Windows示例不适用于Java 8和更早版本:请参见bugs.openjdk.java.net/browse/JDK-8131329
philwalk

也许不适用于开放式JDK,我将对此进行测试,并在这里进行讨论
Wender 18'Jul

抱歉,我曾经在HotSpot上进行过测试,但我确实认为OpenJDK可以使用。
将于

Windows下的Oracle Java需要在星号之前使用反斜杠,而不是正斜杠,尽管我尚未重新测试最新的Java版本或备用Java版本。
philwalk

macOS


29

您可以尝试使用Java -Djava.ext.dirs=jarDirectory http://docs.oracle.com/javase/6/docs/technotes/guides/extensions/spec.html

运行Java时外部jar的目录


3
这是可行的,但请注意,通过-Djava.ext.dirs=之前-jar
Giovanni Funchal

5
java.ext.dirs的工作方式与类路径中的普通jar截然不同。它具有更高的优先级和许可权,它将能够以某种方式覆盖bootsstamp(rt.jar)中的类
Dennis C 2010年

谢谢。在“ java版本“ 1.8.0_221” Java™SE运行时环境(内部版本1.8.0_221-b27)Java HotSpot™64位服务器VM(内部版本25.221-b27,混合模式)上,仅此-D版本传递类路径的工作原理。传统形式则没有。
马特·坎贝尔,

23

正确的

java -classpath "lib/*:." my.package.Program

不正确:

java -classpath "lib/a*.jar:." my.package.Program
java -classpath "lib/a*:."     my.package.Program
java -classpath "lib/*.jar:."  my.package.Program
java -classpath  lib/*:.       my.package.Program

9

如果确实需要动态指定所有.jar文件,则可以使用Shell脚本或Apache Ant。有一个名为Commons Launcher的Commons项目,该项目基本上可以让您将启动脚本指定为ant构建文件(如果您明白我的意思)。

然后,您可以指定以下内容:

<path id="base.class.path">
    <pathelement path="${resources.dir}"/>
    <fileset dir="${extensions.dir}" includes="*.jar" />
    <fileset dir="${lib.dir}" includes="*.jar"/>
</path>

在启动构建文件中,它将使用正确的类路径启动应用程序。




6

敬启者,

我在Windows的MSYS / MinGW shell下发现了这种奇怪的行为。

作品:

$ javac -cp '.;c:\Programs\COMSOL44\plugins\*' Reclaim.java

不起作用:

$ javac -cp 'c:\Programs\COMSOL44\plugins\*' Reclaim.java
javac: invalid flag: c:\Programs\COMSOL44\plugins\com.comsol.aco_1.0.0.jar
Usage: javac <options> <source files>
use -help for a list of possible options

我很确定通配符不会被shell扩展,因为例如

$ echo './*'
./*

(它也与另一个程序(而不是内置程序)一起尝试过,echo结果相同。)

我相信它javac正在尝试扩展它,并且无论参数中是否有分号,它的行为都不同。首先,它可能试图扩展所有看起来像路径的参数。只有到那时,它才会解析它们,-cp并且仅采用以下标记。(请注意,这com.comsol.aco_1.0.0.jar是该目录中的第二个JAR。)这完全是个猜测。

这是

$ javac -version
javac 1.7.0

5

如果您在Eclipse或Netbeans之类的任何IDE外部开发和运行Java应用程序,那么上述所有解决方案都将非常有用。

如果您使用的是Windows 7并且使用Java的Eclipse IDE进行开发,则在使用命令提示符运行Eclipse内置的类文件时可能会遇到问题。

例如,您在Eclipse中的源代码具有以下程序包层次结构:edu.sjsu.myapp.Main.java

您将json.jar作为Main.java的外部依赖项

当您尝试从Eclipse中运行Main.java时,它将正常运行。

但是,当您在Eclipse中编译Main.java之后尝试使用命令提示符运行此命令时,它将发出一些奇怪的错误,提示“ ClassNotDef错误等等”。

我假设您在源代码的工作目录中!

使用以下语法从命令提示符运行它:

  1. javac -cp “。; json.jar” Main.java

  2. java -cp “。; json.jar” edu.sjsu.myapp.Main

    [不要错过。以上]

这是因为您已将Main.java放在edu.sjsu.myapp包中,而java.exe会查找确切的模式。

希望能帮助到你 !!


4

对于Windows,引号是必需的;应该用作分隔符。例如:

java -cp "target\\*;target\\dependency\\*" my.package.Main

4

简短格式:如果您的主体位于jar中,则可能需要另外声明一个'-jar pathTo / yourJar / YourJarsName.jar使其正常工作(即使'YourJarsName.jar'在类路径中)(或表示要回答5年前提出的原始问题:您不需要显式地重新声明每个jar,但是看起来,即使使用java6,您也需要重新声明自己的jar ...)


长格式:(我已经明确指出了这一点,我希望即使是闯入Java的闯入者也可以使用此功能)

像这里的许多内容一样,我使用eclipse导出jar :(文件->导出->“可运行的JAR文件”)。“库处理”蚀(Juno)提供三个选项:

opt1: "Extract required libraries into generated JAR"
opt2: "Package required libraries into generated JAR"
opt3: "Copy required libraries into a sub-folder next to the generated JAR"

通常情况下,我会使用opt2(并且opt1肯定断了),但是在我使用的一个jar中,我发现本地代码与方便的“ jarinjar”技巧相冲突,当您选择该选项时,eclipse会利用这些技巧。即使意识到我需要opt3,然后找到了这个StackOverflow条目,我仍然花了一些时间弄清楚如何在eclipse之外启动我的主程序,所以这对我有用,因为它对其他人有用...


如果您将jar命名为:“ fooBarTheJarFile.jar”,并且所有文件都设置为导出到目录:“ / theFully / qualifiedPath / toYourChosenDir”。

(意味着“导出目的地”字段将显示为:“ / theFully / qualifiedPath / toYourChosenDir / fooBarTheJarFile.jar”)

完成后,您会发现eclipse,然后将所有库放入该导出目录中的名为“ fooBarTheJarFile_lib”的文件夹中,为您提供以下内容:

/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar01.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar02.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar03.jar
/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/SomeOtherJar04.jar

然后,您可以使用以下方法从系统上的任何位置启动:

java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*" -jar  /theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar   package.path_to.the_class_with.your_main.TheClassWithYourMain

(对于Java新手:“ package.path_to.the_class_with.your_main”是声明的包路径,您可以在包含“ main(String [] args){。”的“ TheClassWithYourMain.java”文件的顶部找到。 。}',您希望从Java外部运行)


需要注意的陷阱是:在声明的类路径上的jar列表中仅包含'fooBarTheJarFile.jar'是不够的。您需要显式声明“ -jar”,然后重新声明该jar的位置。

例如,这打破了:

 java -classpath "/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile.jar;/theFully/qualifiedPath/toYourChosenDir/fooBarTheJarFile_lib/*"  somepackages.inside.yourJar.leadingToTheMain.TheClassWithYourMain

用相对路径重述:

cd /theFully/qualifiedPath/toYourChosenDir/;
BREAKS:  java -cp "fooBarTheJarFile_lib/*"                                package.path_to.the_class_with.your_main.TheClassWithYourMain    
BREAKS:  java -cp ".;fooBarTheJarFile_lib/*"                              package.path_to.the_class_with.your_main.TheClassWithYourMain   
BREAKS:  java -cp ".;fooBarTheJarFile_lib/*"   -jar                       package.path_to.the_class_with.your_main.TheClassWithYourMain   
WORKS:   java -cp ".;fooBarTheJarFile_lib/*"   -jar  fooBarTheJarFile.jar package.path_to.the_class_with.your_main.TheClassWithYourMain   

(使用Java版本“ 1.6.0_27”;通过ubuntu 12.04上的OpenJDK 64位服务器VM)


3

我知道如何做的唯一方法是单独进行操作,例如:

setenv CLASSPATH /User/username/newfolder/jarfile.jar:jarfile2.jar:jarfile3.jar:.

希望有帮助!


这可能是08年的唯一方法,但现在已经不复存在了。
simo.3792 2014年

这不是最坏的事情。这是一个hack,但是我在bashrc中设置了这个设置for jar in $(ls $HOME/bin/*.jar); do export CLASSPATH=$jar:$CLASSPATH; done
Devon Peticolas 2015年

3

wepapp的课程:

  > mvn clean install

  > java -cp "webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/tool-jar-1.17.0-SNAPSHOT.jar;webapp/target/webapp-1.17.0-SNAPSHOT/WEB-INF/lib/*" com.xx.xx.util.EncryptorUtils param1 param2

2

您需要单独添加它们。另外,如果您确实只需要指定一个目录,则可以将所有内容解压缩到一个目录中并将其添加到类路径中。但是,我不建议您使用这种方法,因为您可能会在类路径版本控制和不可管理性方面遇到奇怪的问题。


3
这可能是08年的唯一方法,但现在已经不复存在了。
simo.3792

2

不能将/ *设置为-cp的直接解决方案,但我希望您可以使用以下脚本来缓解动态类路径和lib目录的情况。

 libDir2Scan4jars="../test";cp=""; for j in `ls ${libDir2Scan4jars}/*.jar`; do if [ "$j" != "" ]; then cp=$cp:$j; fi; done; echo $cp| cut -c2-${#cp} > .tmpCP.tmp; export tmpCLASSPATH=`cat .tmpCP.tmp`; if [ "$tmpCLASSPATH" != "" ]; then echo .; echo "classpath set, you can now use  ~>         java -cp \$tmpCLASSPATH"; echo .; else echo .; echo "Error please check libDir2Scan4jars path"; echo .; fi; 

针对Linux编写的脚本,也可以针对Windows使用类似的脚本。如果提供了正确的目录作为“ libDir2Scan4jars”的输入;该脚本将扫描所有jar,并创建一个类路径字符串,并将其导出到环境变量“ tmpCLASSPATH”。


2

macOS,当前文件夹

对于macOS Mojave上的Java 13 …

如果所有.jar文件都在同一个文件夹中,请使用将该文件cd设为当前工作目录。验证pwd

对于,-classpath您必须首先列出您的应用程序的JAR文件。使用冒号字符:作为分隔符,在星号后面附加一个星号*以获取所有其他JAR文件。最后,使用您的mainmethod传递类的完整包名称。

例如,对于JAR文件中的应用程序,该应用程序使用包中名为的类中my_app.jarmain方法命名App,该应用程序com.example与同一文件夹中的一些需要的jar一起:

java -classpath my_app.jar:* com.example.App

不适用于Java 8
Greyshack,


1

以适合多个jar和当前目录的类文件的方式设置类路径。

CLASSPATH=${ORACLE_HOME}/jdbc/lib/ojdbc6.jar:${ORACLE_HOME}/jdbc/lib/ojdbc14.jar:${ORACLE_HOME}/jdbc/lib/nls_charset12.jar; 
CLASSPATH=$CLASSPATH:/export/home/gs806e/tops/jconn2.jar:.;
export CLASSPATH

0

我的文件夹中有多个罐子。下面的命令对我JDK1.8有用,以包括该文件夹中存在的所有jar。请注意,如果类路径中有空格,请在引号中包含

视窗

编译: javac -classpath "C:\My Jars\sdk\lib\*" c:\programs\MyProgram.java

运行: java -classpath "C:\My Jars\sdk\lib\*;c:\programs" MyProgram

的Linux

编译: javac -classpath "/home/guestuser/My Jars/sdk/lib/*" MyProgram.java

运行: java -classpath "/home/guestuser/My Jars/sdk/lib/*:/home/guestuser/programs" MyProgram


-1

我正在尝试以jar或Ubuntu中的类的形式运行Java文件。我在两个选项中都失败了。以下例外是其输出。

Download link: https://upload.cat/f694139f88c663b1

java org.statmetrics.Statmetric

要么

java -cp /home/elias/statmetrics/statmetrics.jar:。org.statmetrics.Statmetrics

要么

java -classpath“ /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/*” -jar /home/elias/statmeics/statmetrics.jar org.statmetrics.Statmetrics

Exception in thread "Thread-0" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/adapters/XmlAdapter
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at org.statmetrics.c.a(Unknown Source)
    at org.statmetrics.dw.a(Unknown Source)
    at org.statmetrics.dx.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.adapters.XmlAdapter
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 12 more

我找到了答案:

我的笨蛋

第一步:您必须设置相应的Java:我有Java 11,但是我将第8版设置为Java lib path!-您可以在此处设置Java版本:

  sudo update-alternatives --config java

第二步:然后,通过将路径和文件名更改为相应的路径和文件,运行以下命令:

  java -classpath "/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/*" -jar /home/elias/statmetrics/statmetrics.jar org.statmetrics.Statmetrics

运行成功!

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.