如何从清单文件中不是Main-Class的Jar运行一个类


166

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


只需将它们包装在不同的jar中,使用另一个jar来保存依赖项?
尼克,

11
为什么没有单个主类基于命令行参数调用特定方法(在4种方法中)?
无法

Answers:


215

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

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

2
根据文档,这将不起作用:“为了使此选项起作用,JAR文件的清单必须包含以下行:Main-Class:classname。”
Thomas

“无法从MyJar.jar加载Main-Class清单属性”
Bhushan

10
托马斯是对的。您需要将“ -jar”替换为“ -cp”。查看我更新的代码
lxu4net 2011年

9
@chrisdew提供的答案无需更改/删除Main-Class属性即可更改Jar文件。
Ed Griebel

155

您可以从JAR文件执行具有方法的任何public final static main即使jar文件具有Main-Classdefine

执行主类:

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

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

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

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


10
而且,如果您也希望所有jar都位于classpath的当前目录中(例如,从lib目录运行Main class),则可以使用java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethodNote引起双引号,以./*防止unix机器对其进行扩展。另请注意,这"./*.jar"将无法正常工作。
PetrÚjezdský16年

19

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

    }
}

1
这是一种很好的替代方法!我的jar是使用“ spring-boot:repackage”创建的,因此我无法通过“ -cp”方式运行其他入口类。我不知道spring-boot插件对jar做了什么。在这种情况下,调度类会有所帮助。

6

此答案适用于Spring-boot用户:

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

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

即使您可以通过看到JAR中的类jar tvf yours.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


如果您的jar是可执行文件,该怎么办。即,当您解压缩罐子时,所有类都以“ / BOOT-INF / classes /”
开头

2

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

其次,为什么要以FQCN(com.mycomp.myproj.dir2.MainClass2)和file(com/mycomp/myproj/dir2/MainClass2.class)两次通过该类?

编辑:

似乎java -jar需要指定一个主类。您可以尝试java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...代替。-cp在类路径上设置jar,并使java可以在其中查找主类。


我是按照这里提到的
Bhushan

1
在该页面上:“可以在创建或更新jar文件时使用它。” -因此,这用于设置主类属性,而不是运行jar。
托马斯

1

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

MyJar 1 .jar \ META-INF \ MANIFEST.MF

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

MyJar 2 .jar \ META-INF \ MANIFEST.MF

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

等。然后用 java -jar MyJar2.jar


-4

在pom.xml文件中添加以下插件,并在元素中指定具有完全限定名称的Main Class。

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>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>
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.