关于java:如何从Jar运行一个类,它不是Manifest文件中的Main-Class

How to run a class from Jar which is not the Main-Class in its Manifest file

我有一个包含4个类的JAR,每个类都有主方法。我希望能够根据需要运行其中的每一个。我正在尝试从Linux机器上的命令行运行它。

1
E.g. The name of my JAR is MyJar.jar

它具有如下主要类的目录结构:

1
2
3
4
com/mycomp/myproj/dir1/MainClass1.class
com/mycomp/myproj/dir2/MainClass2.class
com/mycomp/myproj/dir3/MainClass3.class
com/mycomp/myproj/dir4/MainClass4.class

我知道可以在清单文件中指定一个类作为主类。但是有没有什么方法可以让我在命令行上指定一些参数来运行我想要运行的类?

我试过这个:

1
jar cfe MyJar.jar com.mycomp.myproj.dir2.MainClass2 com/mycomp/myproj/dir2/MainClass2.class /home/myhome/datasource.properties /home/myhome/input.txt

我得到了这个错误:

1
com/mycomp/myproj/dir2/MainClass2.class : no such file or directory

(在上面的命令中,/home/myhome/datasource.properties'和'/home/myhome/input.txt'是命令行参数)。


您可以在清单文件中创建不带主类的JAR。然后:

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


您可以从JAR文件执行任何具有public final static main方法的类,即使JAR文件定义了Main-Class

执行主类:

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

public static void main方法执行另一个类:

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

注:第一种使用-jar,第二种使用-cp


除了调用java -jar myjar.jar com.mycompany.Myclass之外,您还可以使清单中的主类成为Dispatcher类。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);

    }
}


首先,jar创建一个jar,不运行它。改为试试java -jar

第二,你为什么两次通过这门课,分别是FQCN(com.mycomp.myproj.dir2.MainClass2)和AS file(com/mycomp/myproj/dir2/MainClass2.class

编辑:

似乎java -jar需要指定一个主类。你可以试试java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...。EDCOX1(6)在类路径上设置jar,使Java可以在那里查找主类。


我认为尼克在评论中简要提到的另一个类似的选择是创建多个包装罐。我没有尝试过,但我认为它们可能是完全空的,而不是清单文件,它应该指定要加载的主类以及将myjar.jar包含到类路径中。

myjar1.jarMETA-INFmanifest.mf

1
2
3
Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir1.MainClass1
Class-Path: MyJar.jar

myjar2.jarMETA-INFmanifest.mf

1
2
3
Manifest-Version: 1.0
Main-Class: com.mycomp.myproj.dir2.MainClass2
Class-Path: MyJar.jar

等。然后用java -jar MyJar2.jar运行它。


在pom.xml文件中添加下面的插件,并在元素中指定具有完全限定名的主类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<plugin>
    <groupId>org.springframework.boot</groupId>
    spring-boot-maven-plugin</artifactId>
    <version>1.2.5.RELEASE</version>
    <configuration>
        <mainClass>**main Class name with full qualified name**</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>