[java] Gradle을 통해 Java 클래스를 실행할 때 시스템 속성 및 매개 변수 전달 문제

빠른 통합 테스트의 일부로 Gradle을 통해 명령 줄 Java 앱을 실행하려고합니다. Maven에서 빌드 스크립트를 이식하고 있는데 exec-maven-plugin. 내 두 가지 큰 요구 사항은 다음과 같습니다.

  • 시스템 속성을 실행 가능한 Java 코드로 전달할 수 있음
  • 실행 가능한 Java 코드에 명령 줄 인수를 전달할 수 있음

빌드 스크립트에서 이러한 속성을 읽으려는 것이 아니라 스크립트가 빌드하고 실행하는 Java 프로그램에서 읽으려고한다는 점에 유의하십시오.

나는 다른 두 SO의 게시물을 발견 한 그 주소 자바 프로그램 Gradle을 통해 실행 : 옹호 사용한다는 대답 한 apply plugin: "application"빌드 파일과 gradle run명령 줄에서 , 그리고 대답은 그 접근 방식을 옹호뿐만 아니라 사용하여 다른 task execute(type:JavaExec)빌드 파일과 gradle execute상기 명령 줄 . 나는 두 가지 접근법을 모두 시도했지만 성공하지 못했습니다.

두 가지 문제가 있습니다.

(1) 시스템 속성을 읽기 위해 Java 실행 파일을 가져올 수 없습니다.

수행 여부 :

build.gradle :

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

명령 줄 :

gradle run -Dmyproperty=myvalue

아니면 이거:

build.gradle :

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

명령 줄 :

gradle execute -Dmyproperty=myvalue

두 경우 모두 myproperty통과하지 못합니다. 에서 실행을 시작하는 코드 MyMain.main (...)myproperty시스템 속성을 null / 누락으로 읽습니다 .

(2) 명령 줄 인수를 전달할 수 없습니다.

이것은 아마도 첫 번째 문제와 관련이 있습니다. 에서은 exec-maven-plugin, 예를 들어, 명령 줄 인수 자체가 시스템 속성을 통해 전달했다. Gradle의 경우입니까, 아니면 명령 줄 인수를 전달하는 다른 방법이 있습니까?

이 변수를 어떻게 얻습니까? 또한 apply plugin: 'application'또는 사용하는 것이 더 낫 task execute (type:JavaExec)습니까?



답변

그것을 알아 냈습니다. 주요 문제는 Gradle이 새 Java 프로세스를 포크 할 때 새 환경에 환경 변수 값을 자동으로 전달하지 않는다는 것입니다. systemProperties작업 또는 플러그인 의 속성을 통해 이러한 변수를 명시 적으로 전달해야합니다 .

다른 문제는 명령 줄 인수를 전달하는 방법을 이해하는 것이 었습니다. 이는 args작업 또는 플러그인 의 속성을 통해 이루어 집니다. Maven과 마찬가지로 exec-maven-plugin, 그것들은 또 다른 시스템 속성을 통해 명령 줄에 전달되어야합니다. 공백으로 구분 된 목록 은 객체 를 받아들이는 split()setting 전에 있어야 합니다. 이전 Maven 이름 인 속성의 이름을 지정했습니다.argsListexec.args

javaExec및 응용 프로그램 플러그인 접근 방식이 모두 유효한 것 같습니다 . 다른 기능 중 일부를 사용하려는 경우 애플리케이션 플러그인 접근 방식을 선호 할 수 있습니다 (배포판을 자동으로 구성하는 등).

해결책은 다음과 같습니다.

JavaExec 접근 방식

명령 줄 :

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()
}

애플리케이션 플러그인 접근 방식

명령 줄 :

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()
}


답변

관련없는 Gradle 소품을 전달하여 애플리케이션의 시스템 속성을 오염시키지 않으려는 사람들을 위해 인수 이름 간격을 지정하는 것이 좋습니다.

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

java ... -Dprefix.my.prop=true 통과 할 것이다 my.prop


답변

나는 gradle을 처음 사용했기 때문에 이것이 필요했고 gradle 4.6에서 나를 위해 작동하는 것이 명령 줄에서 조금 더 쉬워 보입니다. 1 개의 arg 문자열을 구문 분석하는 대신 args 배열을 전달할 수 있으며 한 줄로 모든 속성을 전달할 수있는 방법을 찾았습니다. 아래 결합 :

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=


답변

내가 파티에 늦었을지도 모르지만, “Gradle을 실행하기 전에 소품 설정”을 시도한 사람이 있습니까? 나는 테스트했고 이것도 분명히 작동합니다.

myVar=myVal gradle test

예를 들어 다음과 같이 활성 프로필을 설정할 수 있습니다.

SPRING_PROFILES_ACTIVE=dev  gradle test

이것도 분명히 작동합니다.

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

그주의하십시오 myVar기간으로 구분 될 수 없다; 그렇지 않으면 첫 번째 피리어드 이전의 부분 만 키로 간주됩니다.


답변