Cách chạy một lớp từ Jar không phải là Lớp chính trong tệp Bản kê khai của nó


166

Tôi có một JAR với 4 lớp, mỗi lớp có phương thức Main. Tôi muốn có thể chạy từng người theo nhu cầu. Tôi đang cố gắng chạy nó từ dòng lệnh trên hộp Linux.

E.g. The name of my JAR is MyJar.jar

Nó có cấu trúc thư mục cho các lớp chính như sau:

com/mycomp/myproj/dir1/MainClass1.class
com/mycomp/myproj/dir2/MainClass2.class
com/mycomp/myproj/dir3/MainClass3.class
com/mycomp/myproj/dir4/MainClass4.class

Tôi biết rằng tôi có thể chỉ định một lớp là chính trong tệp Bản kê khai của mình. Nhưng có cách nào để tôi có thể chỉ định một số đối số trên dòng lệnh để chạy bất kỳ lớp nào tôi muốn chạy không?

Tôi đã thử điều này:

jar cfe MyJar.jar com.mycomp.myproj.dir2.MainClass2 com/mycomp/myproj/dir2/MainClass2.class /home/myhome/datasource.properties /home/myhome/input.txt

Và tôi đã nhận được lỗi này:

com/mycomp/myproj/dir2/MainClass2.class : no such file or directory

(Trong lệnh trên, '/home/myhome/datasource.properIES' và '/home/myhome/input.txt' là các đối số dòng lệnh).


Chỉ cần gói chúng trong các lọ khác nhau, sử dụng bình khác để giữ các phụ thuộc?
Nick

11
Tại sao không có lớp chính duy nhất gọi phương thức cụ thể (trong số 4) dựa trên các đối số dòng lệnh?
Không thể nói

Câu trả lời:


215

Bạn có thể tạo bình của mình mà không cần Main-Class trong tệp Manifest của nó. Sau đó :

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

2
Theo tài liệu này sẽ không hoạt động: "Để tùy chọn này hoạt động, tệp kê khai của tệp JAR phải chứa một dòng có dạng Main-Class: classname."
Thomas

"Không thể tải thuộc tính tệp kê khai Lớp chính từ MyJar.jar"
Bhushan

10
Thomas nói đúng. bạn cần thay thế "-jar" bằng "-cp". Xem mã cập nhật của tôi
lxu4net

9
Câu trả lời được cung cấp bởi @chrisdew hoạt động mà không phải thay đổi tệp Jar bằng cách sửa đổi / xóa thuộc tính Main-Class.
Ed Griebel

155

Bạn có thể thực thi bất kỳ lớp nào có public final static mainphương thức từ tệp JAR, ngay cả khi tệp jar có Main-Classđịnh nghĩa .

Thực thi lớp chính:

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

Thực hiện một lớp khác với một public static void mainphương thức:

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

Lưu ý: lần đầu sử dụng -jar, lần thứ hai sử dụng -cp.


10
Và nếu bạn cũng muốn tất cả các tệp trong thư mục hiện tại trên classpath (ví dụ: chạy lớp Main từ thư mục lib), bạn có thể sử dụng java -cp "./*" com.mycomp.myproj.AnotherClassWithMainMethodLưu ý các dấu ngoặc kép xung quanh ./*việc ngăn các máy unix mở rộng nó. Cũng lưu ý rằng "./*.jar"sẽ không hoạt động.
Petr Újezdský

19

Ngoài việc gọi java -jar myjar.jar com.mycompany.Myclass, bạn cũng có thể biến lớp chính trong Manifest của mình thành lớp Dispatcher.

Thí dụ:

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
Đây là một cách thay thế tốt để làm điều đó! Bình của tôi được tạo bằng cách sử dụng "spring-boot: repackage", vì vậy tôi không thể chạy các lớp đầu vào khác theo cách "-cp". Tôi không biết plugin khởi động mùa xuân đã làm gì với jar. Trong trường hợp này, một lớp điều phối giúp.
Chu

6

Câu trả lời này dành cho người dùng Spring-boot:

Nếu JAR của bạn là từ một Spring-bootdự án và được tạo bằng lệnh mvn package spring-boot:repackage, phương thức "-cp" ở trên sẽ không hoạt động. Bạn sẽ nhận được:

Lỗi: Không thể tìm hoặc tải lớp chính your.alternative. Class.path

ngay cả khi bạn có thể nhìn thấy lớp trong JAR bằng cách jar tvf yours.jar.

Trong trường hợp này, hãy chạy lớp thay thế của bạn bằng lệnh sau:

java -cp yours.jar -Dloader.main=your.alternative.class.path org.springframework.boot.loader.PropertiesLauncher

Theo tôi hiểu, lớp Spring-boot org.springframework.boot.loader.PropertiesLauncherphục vụ như một lớp tuyển sinh và-Dloader.main tham số cho nó biết cái gì sẽ chạy.

Tham khảo: https://github.com/spring-projects/spring-boot/issues/20404


Điều gì nếu bình của bạn là thực thi. tức là khi bạn giải nén jar, tất cả các lớp được bắt đầu bằng "/ BOOT-INF / class /"
slashdottir

2

Trước hết jartạo ra một cái bình, và không chạy nó. Thửjava -jar thay thế.

Thứ hai, tại sao bạn vượt qua lớp hai lần, dưới dạng FQCN ( com.mycomp.myproj.dir2.MainClass2) và dưới dạng tệp (com/mycomp/myproj/dir2/MainClass2.class )?

Biên tập:

Có vẻ như nếu java -jaryêu cầu một lớp chính được chỉ định. Bạn có thể thử java -cp your.jar com.mycomp.myproj.dir2.MainClass2 ...thay thế. -cpđặt jar trên đường dẫn lớp và cho phép java tìm kiếm lớp chính ở đó.


Tôi đã làm như đã đề cập ở đây: download.oracle.com/javase/tutorial/deployment/jar/appman.html
Bhushan

1
Từ trang đó: "Nó có thể được sử dụng trong khi tạo hoặc cập nhật tệp jar." - Vì vậy, cái này được sử dụng để đặt thuộc tính lớp chính, không chạy jar.
Thomas

1

Một tùy chọn tương tự khác mà tôi nghĩ Nick đã đề cập ngắn gọn trong các bình luận là tạo ra nhiều lọ bọc. Tôi đã không thử nó, nhưng tôi nghĩ rằng chúng có thể hoàn toàn trống rỗng, ngoài tệp kê khai, sẽ chỉ định lớp chính để tải cũng như đưa MyJar.jar vào đường dẫn lớp.

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

vv Sau đó, chỉ cần chạy nó với java -jar MyJar2.jar


-4

Thêm plugin bên dưới trong tệp pom.xml của bạn và chỉ định Lớp chính với tên đủ điều kiện trong thành phần.

<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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.