วิธีการเรียกใช้คลาสจาก Jar ซึ่งไม่ใช่ Main-Class ในไฟล์ Manifest


166

ฉันมี JAR 4 คลาสแต่ละอันมีวิธีการหลัก ฉันต้องการที่จะสามารถเรียกใช้แต่ละคนตามที่ต้องการ ฉันพยายามเรียกใช้จาก command-line บนกล่อง 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' เป็นอาร์กิวเมนต์บรรทัดคำสั่ง)


เพียงแค่บรรจุพวกเขาในขวดที่แตกต่างกันโดยใช้ jar อื่นเพื่อเก็บการอ้างอิง?
นิค

11
ทำไมไม่มีคลาสหลักเดียวที่เรียกใช้เมธอดเฉพาะ (จาก 4) โดยอิงตามอาร์กิวเมนต์บรรทัดคำสั่ง
บอกไม่ได้

คำตอบ:


215

คุณสามารถสร้าง jar ของคุณโดยไม่มี 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"
Thomas

"ไม่สามารถโหลดแอตทริบิวต์ Manifest Class จาก 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หมายเหตุเครื่องหมายอัญประกาศคู่ล้อมรอบ./*เพื่อป้องกันไม่ให้เครื่องยูนิกซ์ขยายตัว ยังทราบว่า"./*.jar"จะไม่ทำงาน
Petr Újezdský

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
นี่เป็นทางเลือกที่ดีที่จะทำ! โถของฉันถูกสร้างขึ้นโดยใช้ "spring-boot: repackage" ดังนั้นฉันจึงไม่สามารถเรียกใช้คลาสทางเข้าอื่นด้วยวิธี "-cp" ฉันไม่รู้ว่าปลั๊กอินบูทบูตทำอะไรกับขวด ในกรณีนี้คลาส dispatching ช่วย
Zhou

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


เกิดอะไรขึ้นถ้า jar ของคุณสามารถใช้งานได้ เช่นเมื่อคุณเปิดเครื่องรูด jar ทุกคลาสจะนำหน้าด้วย "/ BOOT-INF / คลาส /"
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ตั้งค่า jar บน classpath และเปิดใช้งานจาวาเพื่อค้นหาคลาสหลักที่มี


ฉันทำตามที่กล่าวไว้ที่นี่: download.oracle.com/javase/tutorial/deployment/jar/appman.html
Bhushan

1
จากหน้านั้น: "สามารถใช้งานได้ขณะสร้างหรืออัปเดตไฟล์ jar" - ดังนั้นสิ่งนี้จะถูกใช้เพื่อตั้งค่าแอตทริบิวต์ class หลักไม่ให้เรียกใช้ jar
โทมัส

1

อีกตัวเลือกที่คล้ายกันที่ฉันคิดว่า Nick พูดพาดพิงถึงสั้น ๆ ในความคิดเห็นคือการสร้างขวดกระดาษห่อหลาย ฉันไม่ได้ลอง แต่ฉันคิดว่าพวกเขาอาจจะว่างเปล่าอย่างสมบูรณ์อื่น ๆ นอกเหนือจากไฟล์รายการซึ่งควรระบุคลาสหลักที่จะโหลดเช่นเดียวกับการรวม 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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.