Gradle을 사용하여 실행 가능한 JAR 작성


148

지금까지 Eclipse "Export ..."기능을 통해 실행 가능한 JAR 파일을 작성했지만 빌드 자동화를 위해 IntelliJ IDEA 및 Gradle로 전환했습니다.

여기의 일부 기사는 "application"플러그인을 제안하지만, 이것이 내가 예상 한 결과를 초래하지는 않습니다 (JAR, 시작 스크립트 또는 이와 유사한 것).

"내보내기 ..."대화창에서 Eclipse와 동일한 결과를 얻는 방법은 무엇입니까?

답변:


164

실행 가능한 jar 파일은 매니페스트에 Main-Class 항목을 포함하는 jar 파일 일뿐입니다. 따라서이 항목을 매니페스트에 추가 하려면 jar 작업 만 구성하면됩니다 .

jar {
    manifest {
        attributes 'Main-Class': 'com.foo.bar.MainClass'
    }
}

매니페스트에 클래스 경로 항목을 추가해야 할 수도 있지만 동일한 방식으로 수행됩니다.

http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html을 참조 하십시오.


6
이것은 내가 찾던 것 같습니다. 그러나 : 이미 build.gradle에 종속성을 선언했습니다. 클래스 경로를 수동으로 추가해야합니까 아니면 종속성 선언을 다시 사용할 수 있습니까?
Hannes

'런타임'구성 내에서 라이브러리를 반복하고 연결하여 클래스 경로 속성 값을 작성할 수 있어야합니다.
JB 니 제트

3
'런타임'구성을 포함하지 않는다는 것은 무엇을 의미합니까? 바보 같은 질문에 대해 유감스럽게도, 나는 Gradle을 처음 접합니다 ...
Hannes

gradle java 플러그인은 4 개의 다른 클래스 경로에 해당하는 4 개의 "구성"을 정의합니다 : 컴파일 (Java 파일을 컴파일하는 데 사용됨), testCompile (테스트 Java 소스 파일을 컴파일하는 데 사용됨), 런타임 (응용 프로그램을 실행하는 데 사용됨) 및 testRuntime (테스트 실행에 사용됨). gradle.org/docs/current/userguide/…
JB Nizet

아, 고마워-JAR을 빌드하는 것이 정확하고 관리하는 것보다 낫습니다. 이제 클래스 경로를 만드는 데 어려움을 겪고 있습니다.
Hannes

98

JB Nizet와 Jorge_B의 답변이 모두 맞습니다.

가장 간단한 형태로 Gradle을 사용하여 실행 가능한 JAR을 작성하는 것은 매니페스트에 적절한 항목을 추가하는 입니다. 그러나 클래스 경로에 포함되어야하는 종속성을 갖는 것이 훨씬 일반적이므로이 방법은 실제로 까다로워집니다.

애플리케이션 플러그인은 다른 접근 방법을 제공합니다; 실행 가능한 JAR을 작성하는 대신 다음을 제공합니다.

  • run빌드에서 직접 응용 프로그램을 쉽게 실행할 수 있는 작업
  • installDist빌드 된 JAR, 여기에 종속 된 모든 JAR 및이를 실행할 수있는 프로그램으로 모두 가져 오는 시작 스크립트를 포함하여 디렉토리 구조를 생성 하는 태스크
  • distZip그리고 distTar완전한 응용 프로그램 배포를 포함하는 아카이브 (시작 스크립트와 JAR 파일)을 생성 작업

세 번째 방법은 구성 요소의 코드뿐만 아니라 모든 종속성을 포함하는 실행 가능한 JAR 인 소위 "팻 JAR"을 만드는 것입니다. 이 방법을 사용하는 몇 가지 다른 플러그인이 있습니다. 내가 아는 몇 가지에 대한 링크를 포함 시켰습니다. 나는 더 많은 것이 확신합니다.


그림자와 한 병을 시도했습니다. 한 병만 사용하겠습니다. 더 간단하고 사용하기 쉽습니다. 멋있는! 감사
Jako

불행히도 one-jar은 최신 버전의 Gradle에서 작동하지 않습니다. 예를 들어, 참조 github.com/rholder/gradle-one-jar/issues/34
pharsicle

다음 은 jar 태스크를 수정하여 단일 jar을 빌드하는 단일 라이너 솔루션입니다. 이것이 가장 편리한 것으로 나타났습니다. configurations.runtime단일 jar에서 런타임 종속성을 번들 로 추가해야합니다 .
Quazi Irfan

"응용 프로그램 플러그인"이 필요에 맞게 유연하고 유연하다는 것을 알았습니다. 또한 압축 할 모든 항목을 압축하고 해당 zip에 추가 파일을 포함 / 제외 할 수 있습니다. 또한 사용자 지정 작업을 사용하여 추가 진입 점으로 다른 시작 관리자 스크립트를 추가 할 수도 있습니다.
kinORnirvana

생성 된 .tar/ .zip파일을 어떻게 실행 합니까?
Tobiq

35

다른 사람들이 지적했듯이 jar 파일을 실행하려면 응용 프로그램의 진입 점이 Main-Class매니페스트 파일 의 속성 에서 설정되어야 합니다. 종속성 클래스 파일이 배치되지 않은 Class-Path경우 매니페스트 파일 의 항목 에서 설정해야 합니다.

나는 모든 종류의 플러그인 조합을 시도했으며 실행 가능한 jar를 만드는 간단한 작업과 어쨌든 의존성을 포함하지 않았습니다. 모든 플러그인에는 어떤 식 으로든 부족한 것처럼 보이지만 마침내 원하는대로 얻었습니다. 빌드 디렉토리를 오염시키는 수백만 개의 미니 파일이 아니라 매우 깨끗한 빌드 스크립트 파일이 아니라 신비한 스크립트가 없습니다.

다음은 귀하의 편의를 위해 여기 에서 복사하여 붙여 넣기입니다 .

[방법] 하위 디렉토리에 종속 jar을 포함하는 배포 zip 파일을 작성하고 /lib모든 종속 Class-Path항목을 Manifest 파일의 항목에 추가 하십시오.

apply plugin: 'java'
apply plugin: 'java-library-distribution'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.apache.commons:commons-lang3:3.3.2'
}

// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)

jar {
    // Keep jar clean:
    exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'

    manifest {
        attributes 'Main-Class': 'com.somepackage.MainClass',
                   'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
    }
    // How-to add class path:
    //     /programming/22659463/add-classpath-in-manifest-using-gradle
    //     https://gist.github.com/simon04/6865179
}

여기서 요지로 호스팅됩니다 .

결과는에서 찾을 수 있으며 build/distributions압축이 풀린 내용은 다음과 같습니다.

lib / commons-lang3-3.3.2.jar
MyJarFile.jar

내용 MyJarFile.jar#META-INF/MANIFEST.mf:

매니페스트 버전 : 1.0
기본 클래스 : com.somepackage.MainClass
클래스 경로 : lib / commons-lang3-3.3.2.jar


현재 응용 프로그램 jar도 배포판의 'lib'디렉토리에 있습니다. 최상위 디렉토리로 이동하거나 다음 행을 변경해야합니다. 'Class-Path': configuration.runtime.files.collect { "lib / $ it.name"} .join ( '')} '클래스 경로': configuration.runtime.files.collect { "$ it.name"} .join ( '')}
Marc Nuri

1
@MarcNuri 확실합니까? 내 응용 프로그램이 접근 방식을 사용했는데, 현재 응용 프로그램 항아리였다 되지 에서 lib생성 된 zip / tar 파일의 디렉토리, 오히려 있었다 lib이 대답에서 알 수 있듯이, '부모 디렉토리. 이 솔루션은 저에게 완벽하게 작동하는 것 같습니다.
thejonwithnoh

1
@thejonwithnoh 죄송합니다, 당신 말이 맞아요. "java-library-distribution"플러그인을 사용하도록 제안 된 솔루션을 보지 못했습니다. 내 경우에는 내가 단지 (jar 파일의 모든 주요 차이점과 동일한 작업을 수행하는 "응용 프로그램"플러그인을 사용하고 포함 은 "LIB"디렉토리에있는 응용 프로그램 항아리). 따라서 변화 "lib/$it.name"하는 "$it.name"일을 할 것입니다.
Marc Nuri

28

나를위한 최소한의 노력 솔루션은 gradle-shadow-plugin 을 사용하는 것이 었습니다

플러그인을 적용하는 것 외에도 다음을 수행해야합니다.

메인 클래스를 매니페스트에 넣도록 jar 작업을 구성하십시오.

jar {
  manifest {
   attributes 'Main-Class': 'com.my.app.Main'
  }
}

gradle 작업을 실행하십시오.

./gradlew shadowJar

build / libs / 에서 app-version-all.jar 을 가져옵니다.

마지막으로 다음을 통해 실행하십시오.

java -jar app-version-all.jar

2
전체 build.gradle 는 다음과 같습니다 .
Brad Turek

이 빌드를 수행하면 BUILD SUCCESSFUL이 발생하지만 java -jar build / libs / core-all-1.0.jar로 jar 파일을 실행하려고하면 다음 오류가 발생합니다. 오류 : 기본 클래스 scanners.exchange를 찾거나로드 할 수 없습니다. 주요 원인 : java.lang.ClassNotFoundException : scanners.exchange.Main이 문제를 해결하는 방법을 알고 있습니까?
Luka Lopusina 2016 년

@LukaLopusina 지정한 클래스가 JAR 파일에 없습니다. kotlin을 사용하는 경우을 말해야 'com.my.app.MainKt'합니다. 더 많은 정보가 없으면 더 도와 드릴 수 없습니다.
byxor

현재 플러그인 Shadow v5. +는 Gradle 5.0 이상 및 Java 7 이상과 호환됩니다.
Zon

5

'installApp'태스크를 시도 했습니까? 시작 스크립트 세트로 전체 디렉토리를 작성하지 않습니까?

http://www.gradle.org/docs/current/userguide/application_plugin.html


내가 이해 한 바에 따르면 파일을 installApp만들지 않습니다 META-INF/MANIFEST.MF. 내가 뭔가 잘못하고 있습니까?
6:14에

1
Application PlugininstallApp 의 작업 목록에 작업이 표시 되지 않습니다 . 그 대신에 의미 했습니까 ? installDist
Quazi Irfan

2
예, Gradle 3.0에서 installApp이름이 변경되었습니다 installDist. 릴리스 노트 는 다음과 같습니다 .
Quazi Irfan

4

Konstantin에게 감사합니다. 미묘한 차이가 거의 없었습니다. 어떤 이유로 든 jar 매니페스트의 일부로 메인 클래스를 지정하는 것은 효과가 없었으며 대신 mainClassName 속성을 원했습니다. 다음은 build.gradle의 스 니펫이며 작동하는 모든 것을 포함합니다.

plugins {
  id 'java' 
  id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
    baseName = 'myapp'
}

gradle shadowJar를 실행 한 후 빌드 폴더에 myapp- {version} -all.jar이 있으며 java -jar myapp- {version} -all.jar로 실행할 수 있습니다.


3

모듈 설정 (또는 프로젝트 구조)에서 jar 이슈를 정의 할 수 있습니다.

  • 종속성이있는 모듈에서 모듈> 모듈 설정 열기> 아티팩트> +> JAR>을 마우스 오른쪽 단추로 클릭하십시오.
  • 메인 클래스를 설정하십시오.

그런 다음 빌드 메뉴에서 "빌드 아티팩트 ..."를 클릭하는 것만 큼 쉽게 항아리를 만들 수 있습니다. 보너스로 모든 의존성을 단일 jar로 패키징 할 수 있습니다.

IntelliJ IDEA 14 Ultimate에서 테스트되었습니다.


2

나는 솔루션에 대한 꽤 많은 링크를 확인하고 마침내 아래 언급 된 단계를 수행하여 작동하게했습니다. Gradle 2.9를 사용하고 있습니다.

build, gradle 파일에서 다음을 변경하십시오.

  1. 언급 플러그인 :

    apply plugin: 'eu.appsatori.fatjar'
  2. 빌드 스크립트를 제공하십시오.

    buildscript {
    repositories {
        jcenter()
    }
    
    dependencies {
        classpath "eu.appsatori:gradle-fatjar-plugin:0.3"
    }
    }
  3. 메인 클래스를 제공하십시오 :

    fatJar {
      classifier 'fat'
      manifest {
        attributes 'Main-Class': 'my.project.core.MyMainClass'
      }
      exclude 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.SF'
    }
  4. fatjar을 작성하십시오.

    ./gradlew clean fatjar
  5. / build / libs /에서 fatjar을 실행하십시오.

    java -jar MyFatJar.jar

1
2019 년부터 :이 제안은 작동하지 않습니다. fatjar에는 의존성이 포함되어 있지 않습니다
carl

1

SpringBoot 플러그인을 사용할 수 있습니다 :

plugins {
  id "org.springframework.boot" version "2.2.2.RELEASE"
}

항아리 만들기

gradle assemble

그런 다음 실행하십시오.

java -jar build/libs/*.jar

참고 :이 플러그인을 사용하기 위해 프로젝트가 SpringBoot 프로젝트 일 필요는 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.