我有一个包含 4 个类的 JAR,每个类都有 Main 方法。我希望能够根据需要运行其中的每一个。我正在尝试从 Linux 机器上的命令行运行它。
E.g. The name of my JAR is MyJar.jar
主要类的目录结构如下:
com/mycomp/myproj/dir1/MainClass1.class
com/mycomp/myproj/dir2/MainClass2.class
com/mycomp/myproj/dir3/MainClass3.class
com/mycomp/myproj/dir4/MainClass4.class
我知道我可以在我的清单文件中指定一个类作为主类。但是有什么方法可以让我在命令行上指定一些参数来运行我想运行的任何类?
我试过这个:
jar cfe MyJar.jar com.mycomp.myproj.dir2.MainClass2 com/mycomp/myproj/dir2/MainClass2.class /home/myhome/datasource.properties /home/myhome/input.txt
我得到了这个错误:
com/mycomp/myproj/dir2/MainClass2.class : no such file or directory
(在上述命令中,'/home/myhome/datasource.properties' 和 '/home/myhome/input.txt' 是命令行参数)。
您可以在其 Manifest 文件中创建没有 Main-Class 的 jar。然后 :
java -cp MyJar.jar com.mycomp.myproj.dir2.MainClass2 /home/myhome/datasource.properties /home/myhome/input.txt
您可以从 JAR 文件中执行 任何 具有 public static void main
方法的类,即使 jar 文件定义了 Main-Class
。
执行主类:
java -jar MyJar.jar // will execute the Main-Class
使用 public static void main
方法执行另一个类:
java -cp MyJar.jar com.mycomp.myproj.AnotherClassWithMainMethod
注意:第一个使用 -jar
,第二个使用 -cp
。
java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethod
注意 ./*
周围的双引号,防止 unix 机器扩展它。另请注意,"./*.jar"
不起作用。
此答案适用于 Spring-boot 用户:
如果您的 JAR 来自 Spring-boot
项目并使用命令 mvn package spring-boot:repackage
创建,则上述“-cp”方法将不起作用。你会得到:
错误:无法找到或加载主类 your.alternative.class.path
即使您可以通过 jar tvf yours.jar
看到 JAR 中的类。
在这种情况下,请通过以下命令运行您的替代类:
java -cp yours.jar -Dloader.main=your.alternative.class.path org.springframework.boot.loader.PropertiesLauncher
据我了解,Spring-boot 的 org.springframework.boot.loader.PropertiesLauncher
类作为调度入口类,-Dloader.main
参数告诉它要运行什么。
参考:https://github.com/spring-projects/spring-boot/issues/20404
除了调用 java -jar myjar.jar com.mycompany.Myclass
,您还可以将 Manifest 中的主类设为 Dispatcher 类。
例子:
public class Dispatcher{
private static final Map<String, Class<?>> ENTRY_POINTS =
new HashMap<String, Class<?>>();
static{
ENTRY_POINTS.put("foo", Foo.class);
ENTRY_POINTS.put("bar", Bar.class);
ENTRY_POINTS.put("baz", Baz.class);
}
public static void main(final String[] args) throws Exception{
if(args.length < 1){
// throw exception, not enough args
}
final Class<?> entryPoint = ENTRY_POINTS.get(args[0]);
if(entryPoint==null){
// throw exception, entry point doesn't exist
}
final String[] argsCopy =
args.length > 1
? Arrays.copyOfRange(args, 1, args.length)
: new String[0];
entryPoint.getMethod("main", String[].class).invoke(null,
(Object) argsCopy);
}
}
我认为尼克在评论中简要提到的另一个类似选项是创建多个包装罐。我没有尝试过,但我认为除了清单文件之外它们可能是完全空的,清单文件应该指定要加载的主类以及将 MyJar.jar 包含到类路径中。
MyJar1.jar\META-INF\MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir1.MainClass1
Class-Path: MyJar.jar
MyJar2.jar\META-INF\MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir2.MainClass2
Class-Path: MyJar.jar
等等然后用 java -jar MyJar2.jar
运行它
首先 jar
创建一个 jar,但不运行它。请改用 java -jar
。
其次,你为什么要通过两次类,作为 FQCN (com.mycomp.myproj.dir2.MainClass2
) 和作为文件 (com/mycomp/myproj/dir2/MainClass2.class
)?
编辑:
似乎 java -jar
需要指定一个主类。您可以改用 java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...
。 -cp
在类路径中设置 jar 并使 java 能够在那里查找主类。