Як запустити клас з Jar, який не є основним класом у файлі Manifest


166

У мене є JAR з 4-х класів, у кожному є метод 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

Я знаю, що я можу вказати один клас як основний у своєму файлі Manifest. Але чи є спосіб, за допомогою якого я можу вказати якийсь аргумент у командному рядку для запуску того класу, який я хочу запустити?

Я спробував це:

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) на основі аргументів командного рядка?
Не можу сказати

Відповіді:


215

Ви можете створити свою банку без основного класу у файлі Manifest. Тоді :

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"
Bhushan

10
Томас має рацію. вам потрібно замінити "-jar" на "-cp". Дивіться мій оновлений код
lxu4net

9
Відповідь, надана @chrisdew, працює без необхідності змінити файл Jar, змінивши / видаливши атрибут Main-Class.
Ed Griebel

155

Ви можете виконати будь-який клас, у якого є public final static mainметод з файлу JAR, навіть якщо файл 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.


10
І якщо ви також хочете, щоб усі банки в поточному каталозі були також на classpath (наприклад, запуск головного класу з каталогу lib), ви можете використовувати java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethodПримітка подвійних лапок навколо ./*запобігання розширенню Unix-машин. Також зауважте, що "./*.jar"не вийде.
Петро Újezdský

19

Окрім дзвінків java -jar myjar.jar com.mycompany.Myclass, ви також можете зробити основний клас у своєму Manifest класом диспетчера.

Приклад:

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
Це хороший альтернативний спосіб зробити це! Моя баночка була створена за допомогою "spring-boot: перепаковка", тому я просто не можу запускати інші вхідні класи "-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/isissue/20404


Що робити, якщо ваша банка виконується. тобто, коли ви розпакуєте банку, усім класам передує "/ BOOT-INF / class /"
slashdottir

2

Перш за все 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встановлює банку на classpath і дозволяє java шукати там основний клас.


Я зробив, як тут говорилося: download.oracle.com/javase/tutorial/deployment/jar/appman.html
Bhushan

1
З цієї сторінки: "Його можна використовувати під час створення або оновлення файлу jar". - Отже, це використовується для встановлення атрибута основного класу, а не для запуску jar.
Томас

1

Ще один подібний варіант, на який я думаю, що Нік коротко нагадав у коментарях, - це створити кілька баночок для обгортки. Я не пробував цього, але думаю, що вони можуть бути абсолютно порожніми, крім файлу маніфесту, який повинен визначати основний клас для завантаження, а також включення MyJar.jar до classpath.

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.