我有一个有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

我知道我可以在我的Manifest文件中指定一个类为主。但是是否有任何方法可以让我在命令行上指定一些参数来运行我希望运行的任何类?

我试了一下:

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'是命令行参数)。


首先,jar创建了一个jar,但不运行它。试试java -jar吧。

其次,为什么要传递两次类,分别是FQCN (com. mycomp.myprojproject .dir2. mainclass2)和文件(com/ mycomp/myprojproject /dir2/ mainclass2 .class)?

编辑:

似乎java -jar需要指定一个主类。你可以试试java -cp your.jar com. mycom.myproj.dir2。MainClass2……代替。-cp在类路径上设置jar,并允许Java在那里查找主类。


你可以在Manifest文件中创建没有Main-Class的jar。然后:

java -cp MyJar.jar com.mycomp.myproj.dir2.MainClass2 /home/myhome/datasource.properties /home/myhome/input.txt

除了调用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);

    }
}

我认为Nick在评论中简要提到的另一个类似选项是创建多个包装器罐。我还没有尝试过,但我认为除了清单文件之外,它们可以完全为空,清单文件应该指定要加载的主类以及将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文件执行任何具有公共静态void main方法的类,即使JAR文件已经定义了main - class。

执行主类:

java -jar MyJar.jar  // will execute the Main-Class

使用公共静态void main方法执行另一个类:

java -cp MyJar.jar com.mycomp.myproj.AnotherClassWithMainMethod

注意:第一个使用-jar,第二个使用-cp。


这个答案适用于spring boot用户:

如果您的JAR来自Spring-boot项目,并且使用命令mvn package Spring-boot:repackage创建,那么上面的“-cp”方法将不起作用。你会得到:

错误:无法找到或加载主类your.alternative.class.path

即使您可以在JAR by JAR tvf . JAR中看到类。

在这种情况下,通过以下命令运行您的替代类:

java -cp yours.jar -Dloader.main=your.alternative.class.path org.springframework.boot.loader.PropertiesLauncher

正如我所理解的,Spring-boot的org.springframework.boot.loader.PropertiesLauncher类充当调度入口类,而-Dloader. properties类充当调度入口类。主参数告诉它要运行什么。

参考:https://github.com/spring-projects/spring-boot/issues/20404