Как запустить класс из 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.