Sự cố khi chuyển các thuộc tính và tham số hệ thống khi chạy lớp Java qua Gradle


82

Tôi đang cố gắng chạy một ứng dụng Java dòng lệnh qua Gradle như một phần của thử nghiệm tích hợp nhanh. Tôi đang chuyển các tập lệnh xây dựng của mình từ Maven, nơi điều này đã được thực hiện dễ dàng exec-maven-plugin. Hai yêu cầu lớn của tôi là:

  • Có thể chuyển các thuộc tính hệ thống sang mã Java thực thi
  • Có thể chuyển args dòng lệnh sang mã Java thực thi

Xin lưu ý rằng tôi không cố đọc các thuộc tính này trong tập lệnh xây dựng, tôi đang cố đọc chúng trong chương trình Java mà tập lệnh xây dựng và thực thi.

Tôi đã tìm thấy hai bài đăng SO khác đề cập đến việc thực thi chương trình Java thông qua Gradle: một bài có câu trả lời ủng hộ việc sử dụng apply plugin: "application"trong tệp xây dựng và gradle runtại dòng lệnhmột bài đăng khác có câu trả lời ủng hộ cách tiếp cận đó cũng như sử dụng task execute(type:JavaExec)trong tệp xây dựng và gradle executetại dòng lệnh . Tôi đã thử cả hai cách tiếp cận và không thành công.

Tôi có hai vấn đề:

(1) Tôi không thể tải tệp thực thi Java để đọc các thuộc tính hệ thống

Cho dù tôi làm điều này:

build.gradle :

apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"

Dòng lệnh :

gradle run -Dmyproperty=myvalue

Hoặc cái này:

build.gradle :

task execute (type:JavaExec) {
    main = "com.mycompany.MyMain"
    classpath = sourceSets.main.runtimeClasspath 
}

Dòng lệnh :

gradle execute -Dmyproperty=myvalue

Trong cả hai trường hợp, mypropertykhông vượt qua được. Mã bắt đầu chạy từ MyMain.main (...)đọc thuộc tính mypropertyhệ thống là null / thiếu.

(2) Tôi không thể chuyển đối số dòng lệnh

Điều này có lẽ liên quan đến vấn đề đầu tiên. Trong exec-maven-pluginví dụ, args dòng lệnh là mình thông qua vào thông qua một tài sản của hệ thống. Đó là trường hợp của Gradle hay có cách nào khác để truyền các đối số dòng lệnh?

Làm cách nào để truy cập các biến này? Ngoài ra, nó là tốt hơn để sử dụng apply plugin: 'application'hoặc task execute (type:JavaExec)?

Câu trả lời:


123

Tìm ra. Vấn đề chính là khi Gradle tạo một quy trình Java mới, nó không tự động chuyển các giá trị biến môi trường cùng với môi trường mới. Người ta phải chuyển các biến này một cách rõ ràng thông qua thuộc systemPropertiestính của tác vụ hoặc plugin.

Vấn đề khác là hiểu cách chuyển args dòng lệnh; chúng thông qua thuộc argstính trên tác vụ hoặc plugin. Như với Maven exec-maven-plugin, chúng phải được chuyển vào dòng lệnh thông qua một thuộc tính hệ thống khác, dưới dạng một danh sách được phân cách bằng dấu cách mà sau đó cần phải có split()trước khi thiết lập args, chấp nhận Listcác đối tượng. Tôi đã đặt tên cho tài sản exec.args, đó là tên Maven cũ.

Có vẻ như cả javaExecphương pháp tiếp cận plugin và ứng dụng đều hợp lệ. Người ta có thể ủng hộ cách tiếp cận plugin ứng dụng nếu người ta muốn sử dụng một số tính năng khác của nó (tự động kết hợp một bản phân phối, v.v.)

Đây là các giải pháp:

Phương pháp tiếp cận JavaExec

Dòng lệnh :

gradle execute -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"

build.gradle :

task execute (type:JavaExec) {

    main = "com.myCompany.MyMain"
    classpath = sourceSets.main.runtimeClasspath 

    /* Can pass all the properties: */
    systemProperties System.getProperties()

    /* Or just each by name: */
    systemProperty "myvariable", System.getProperty("myvariable")

    /* Need to split the space-delimited value in the exec.args */
    args System.getProperty("exec.args", "").split()    
}

Phương pháp tiếp cận plugin ứng dụng

Dòng lệnh :

gradle run -Dmyvariable=myvalue -Dexec.args="arg1 arg2 arg3"

build.gradle :

apply plugin: 'application'
mainClassName = "com.mycompany.MyMain"
run {    
    /* Can pass all the properties: */
    systemProperties System.getProperties()

    /* Or just each by name: */
    systemProperty "myvariable", System.getProperty("myvariable")

    /* Need to split the space-delimited value in the exec.args */
    args System.getProperty("exec.args", "").split()    
}

3
Tôi nghĩ rằng đó phải là System.getProperties () (chữ S).
orlanthi

1
Nếu bạn đang sử dụng 2.xx gradle, bạn cũng có thể sử dụng sau đây: -systemProperty "myvariable", "${myvariable}"
eadjei

1
Cảm ơn bạn! Tôi đã cố gắng chạy các bài kiểm tra Cucumber và muốn chuyển các biến môi trường cho JVM. Tôi vừa đặt "systemProperties System.getProperties ()" trong thử nghiệm {} thay vì chạy {}
Svante

1
Xin lưu ý rằng phân tách mặc định không cho phép các đối số có dấu cách, ví dụ -Dexec.args="--greeting 'hello there'"- sẽ không hoạt động, cần đặt dấu phân cách khác.
Ivan Balashov

3
Sử dụng: args System.getProperty ("execute.args", "") .split () để tránh ngoại lệ con trỏ null nếu không cung cấp args. Ví dụ: ngay cả 'nhiệm vụ gradle' cũng sẽ xuất hiện một ngoại lệ với bản dựng được đề xuất .gradle
Mike Hanafey

12

Đối với những người có thể không muốn làm ô nhiễm các thuộc tính hệ thống của ứng dụng của bạn bằng cách chuyển các đạo cụ Gradle không liên quan, tôi khuyên bạn nên đặt tên cho các đối số của mình.

tasks.withType(JavaExec) {
    System.properties.each { k,v->
        if (k.startsWith("prefix.")) {
            systemProperty k - "prefix.", v
        }
    }
}

java ... -Dprefix.my.prop=true sẽ vượt qua my.prop


3

Tôi mới làm quen với gradle nên tôi cần cái này và những gì đang làm việc với tôi với gradle 4.6 có vẻ dễ dàng hơn một chút cho dòng lệnh. Thay vì phân tích cú pháp 1 chuỗi đối số, bạn có thể truyền một mảng args và tôi đã tìm ra cách để truyền vào tất cả thuộc tính bằng một dòng. Kết hợp bên dưới:

apply plugin: 'java'
apply plugin: 'org.springframework.boot'    <- for my project

task runApp(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath

  main = 'testit.TomcatApp'

  // arguments to pass to the application
  //  args 'myarg1 -rest'    <- came in as 1 string

  args = ["--myarg1 with spaces even", "--myarg2"]

  // and to pass in all -D system property args:
  systemProperties = System.properties
}

gradle run -Dwhatever=xxx -Dmyarg2=hey

// Java reading them:
public static void main(String[] args) {
    for ( int i = 0; i < args.length; i++ )
        {
        logger.info( "** args [" + i + "] =" + args[i] + "=" );
        }
    logger.info( "** -Dwhatever =" + System.getProperty("whatever") + "=" );
    logger.info( "** -Dmyarg2 =" + System.getProperty("myarg2") + "=" );

[main] INFO testit.TomcatApp - ** args [0] =--myarg1 with spaces even=
[main] INFO testit.TomcatApp - ** args [1] =--myarg2=
[main] INFO testit.TomcatApp - ** -Dwhatever =xxx=
[main] INFO testit.TomcatApp - ** -Dmyarg2 =hey=

-2

Có lẽ tôi đến muộn cho bữa tiệc, nhưng có ai đã thử với "đặt chỗ dựa trước khi thực hiện gradle" chưa? Tôi đã thử nghiệm và nó cũng hoạt động.

myVar=myVal gradle test

Ví dụ: bạn có thể đặt cấu hình hoạt động như:

SPRING_PROFILES_ACTIVE=dev  gradle test

Chúng cũng hoạt động, rõ ràng: (đã thử nghiệm)

set myVar=myVal && gradle test      # for windows
export myVar=myVal && gradle test   # for linux and mac

Hãy cảnh giác rằng myVarkhông thể tách biệt thời gian; hoặc nếu không, chỉ phần trước khoảng thời gian đầu tiên sẽ được lấy làm khóa.

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.