如何从 Jar 运行一个类,该类不是其清单文件中的主类

问题描述 投票:0回答:6

我有一个包含 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'是命令行参数)。

java jar executable-jar
6个回答
275
投票

您可以在其清单文件中创建没有 Main-Class 的 jar。然后:

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

220
投票

您可以从 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


41
投票

这个答案适用于 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.launch.PropertiesLauncher

据我了解,Spring-boot的

org.springframework.boot.loader.launch.PropertiesLauncher
类作为调度入口类,
-Dloader.main
参数告诉它要运行什么。

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


24
投票

除了调用

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

    }
}

3
投票

我认为尼克在评论中简要提到的另一个类似选项是创建多个包装罐。我还没有尝试过,但我认为除了清单文件之外,它们可能完全是空的,清单文件应该指定要加载的主类以及将 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

运行它

1
投票

首先

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 能够在那里查找主类。

© www.soinside.com 2019 - 2024. All rights reserved.