Как запустить класс из Jar, который не является главным классом в его файле манифеста


167

У меня есть JAR с 4 классами, у каждого есть метод Main. Я хочу быть в состоянии управлять каждым из них согласно потребности. Я пытаюсь запустить его из командной строки на Linux box.

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»).


Просто упакуйте их в разные банки, используя другой файл для хранения зависимостей?
Ник

11
Почему бы не иметь единый основной класс, который вызывает конкретный метод (из 4) на основе аргументов командной строки?
Не могу сказать

Ответы:


216

Вы можете создать свой кувшин без Main-Class в файле Manifest. Затем :

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

2
Согласно документу это не сработает: «Чтобы эта опция работала, манифест файла JAR должен содержать строку вида Main-Class: classname.»
Томас,

«Не удалось загрузить атрибут манифеста основного класса из MyJar.jar»
Бхушан,

10
Томас прав. вам нужно заменить "-jar" на "-cp". Смотрите мой обновленный код
lxu4net

9
Ответ, предоставленный @chrisdew, работает без необходимости изменения файла Jar путем изменения / удаления атрибута Main-Class.
Эд Грибель

157

Вы можете выполнить любой класс, у которого есть public final static mainметод из файла JAR, даже если у файлаMain-Class JAR есть определенный .

Выполнить основной класс:

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-файлы в текущем каталоге также находились в пути к классам (например, запускал основной класс из каталога lib), вы можете использовать java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethodдвойные кавычки, чтобы не ./*допустить его расширения на машинах unix. Также обратите внимание, что "./*.jar"не будет работать.
Петр Рождский

19

Помимо вызова java -jar myjar.jar com.mycompany.Myclass, вы также можете сделать основной класс в вашем манифесте классом 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". Я не знаю, что плагин весенней загрузки сделал с флягой. В этом случае помогает диспетчерский класс.
Чжоу

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

Как я понял, org.springframework.boot.loader.PropertiesLauncherкласс Spring-boot служит диспетчерским входным классом, а-Dloader.main параметр указывает ему, что запускать.

Ссылка: https://github.com/spring-projects/spring-boot/issues/20404


Что делать, если ваша банка исполняемая. т.е. когда вы распаковываете банку, всем классам предшествует "/ BOOT-INF / classes /"
slashdottir

2

Прежде всего 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 искать там основной класс.


Я сделал, как упоминалось здесь: download.oracle.com/javase/tutorial/deployment/jar/appman.html
Бхушан,

1
С этой страницы: «Его можно использовать при создании или обновлении файла JAR». - Так что это используется для установки атрибута основного класса, а не для запуска фляги.
Томас

1

Еще одна похожая опция, на которую, как мне кажется, Ник кратко упомянул в комментариях, - это создание нескольких jar-пакетов. Я не пробовал, но думаю, что они могут быть полностью пустыми, кроме файла манифеста, в котором должен быть указан основной класс для загрузки, а также включение 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 и укажите основной класс с полным именем в элементе.

<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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.