1. 소개

이 예제에서는 spring-boot-thin-launcher 프로젝트를 사용하여 Spring Boot 프로젝트를 얇은 JAR 파일로 빌드하는 방법 을 살펴볼 것 입니다.

Spring Boot는 하나의 실행 가능한 아티팩트에 애플리케이션 코드와 모든 종속 항목이 모두 포함 된 "뚱뚱한"JAR 배포로 유명합니다.

Boot는 마이크로 서비스 개발에도 널리 사용됩니다. 많은 아티팩트에 동일한 의존성을 반복해서 포함하는 것이 중요한 자원 낭비가 될 수 있기 때문에 이것은 때때로 "뚱뚱한 JAR"접근 방식과 상충 될 수 있습니다.

2. 전제 조건

우선, 당연히 Spring Boot 프로젝트가 필요합니다. 이 기사에서는 Maven 빌드와 가장 일반적인 구성의 Gradle 빌드를 살펴 보겠습니다.

모든 빌드 시스템과 빌드 구성을 다룰 수는 없지만 특정 설정에 적용 할 수 있어야하는 일반적인 원칙을 충분히 살펴볼 것입니다.

2.1. Maven 프로젝트

Maven으로 빌드 된 Boot 프로젝트에서 우리는 프로젝트의 pom.xml 파일, 부모 또는 조상 중 하나에 Spring Boot Maven 플러그인을 구성해야합니다 .

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>    
</plugin>

Spring Boot 의존성의 버전은 일반적으로 참조 프로젝트에서와 같이 BOM을 사용하거나 상위 POM에서 상속하여 결정됩니다.

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.0</version>
    <relativePath/>
</parent>

2.2. Gradle 프로젝트

Gradle로 빌드 된 Boot 프로젝트에는 Boot Gradle 플러그인이 있습니다.

buildscript {
    ext {
        springBootPlugin = 'org.springframework.boot:spring-boot-gradle-plugin'
        springBootVersion = '2.4.0'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("${springBootPlugin}:${springBootVersion}")
    }
}

// elided

apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

springBoot {
    mainClassName = 'com.baeldung.DemoApplication'
}

이 기사에서는 Boot 2.x 이상 프로젝트 만 고려할 것입니다. Thin Launcher는 이전 버전도 지원하지만 단순성을 위해 생략 한 약간 다른 Gradle 구성이 필요합니다. 자세한 내용은 프로젝트 홈페이지를 참조하십시오.

3. Thin JAR을 만드는 방법?

Spring Boot Thin Launcher는 아카이브 자체에 번들로 포함 된 파일에서 아티팩트의 의존성을 읽고 Maven 저장소에서 다운로드 한 다음 마지막으로 애플리케이션의 기본 클래스를 시작하는 작은 라이브러리입니다.

따라서 라이브러리로 프로젝트를 빌드 할 때 코드가 포함 된 JAR 파일, 의존성을 열거하는 파일 및 위 작업을 수행하는 라이브러리의 기본 클래스를 얻습니다.

물론 간단한 설명보다 약간 더 미묘한 차이가 있습니다. 이 기사의 뒷부분에서 몇 가지 주제에 대해 자세히 설명하겠습니다.

4. 기본 사용법

이제 일반 Spring Boot 애플리케이션에서 "얇은"JAR을 빌드하는 방법을 살펴 보겠습니다.

Thin Launcher를 제어하는 ​​선택적 추가 명령 줄 인수와 함께 일반적인 java -jar <my-app-1.0.jar>을 사용 하여 애플리케이션을 시작합니다. 다음 섹션에서 몇 가지를 살펴 보겠습니다. 프로젝트의 홈페이지에는 전체 List이 포함되어 있습니다.

4.1. Maven 프로젝트

Maven 프로젝트에서 사용자 정의 "thin"레이아웃에 대한 의존성을 포함하도록 Boot 플러그인 (섹션 2.1 참조)의 선언을 수정해야합니다.

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <dependencies>
        <!-- The following enables the "thin jar" deployment option. -->
        <dependency>
            <groupId>org.springframework.boot.experimental</groupId>
            <artifactId>spring-boot-thin-layout</artifactId>
            <version>1.0.11.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>

실행 프로그램 으로부터 의존성을 읽을 의 pom.xml 파일에 그에서 생성 된 JAR에서 메이븐 저장 META-INF / 받는다는 디렉토리.

예를 들어 mvn install을 사용하여 평소와 같이 빌드를 수행합니다 .

씬 빌드와 팻 빌드 (예 : 여러 모듈이있는 프로젝트)를 모두 생성하려면 전용 Maven 프로필에서 사용자 지정 레이아웃을 선언 할 수 있습니다.

4.2. Maven 및 의존성 : thin.properties

Maven pom.xml 외에 thin.properties 파일을 생성하도록 할 수도 있습니다 . 이 경우 파일에는 전 이적 의존성을 포함하여 전체 의존성 List이 포함되며 실행기는 pom.xml 보다 선호합니다 .

이를위한 mojo (플러그인)는 spring-boot-thin-maven-plugin : properties이며 , 기본적 으로 src / main / resources / META-INF에 thin.properties 파일을 출력 하지만 다음과 같이 위치를 지정할 수 있습니다. thin.output 특성 :

$ mvn org.springframework.boot.experimental:spring-boot-thin-maven-plugin:properties -Dthin.output=.

목표가 성공하려면 기본 디렉토리를 유지 했더라도 출력 디렉토리가 존재해야합니다.

4.3. Gradle 프로젝트

대신 Gradle 프로젝트에서 전용 플러그인을 추가합니다.

buildscript {
    ext {
        //...
        thinPlugin = 'org.springframework.boot.experimental:spring-boot-thin-gradle-plugin'
        thinVersion = '1.0.11.RELEASE'
    }
    //...
    dependencies {
        //...
        classpath("${thinPlugin}:${thinVersion}")
    }
}

//elided

apply plugin: 'maven'
apply plugin: 'org.springframework.boot.experimental.thin-launcher'

씬 빌드를 얻기 위해 Gradle에 thinJar 작업 을 실행하도록 지시합니다 .

~/projects/baeldung/spring-boot-gradle $ ./gradlew thinJar

4.4. Gradle 및 의존성 : pom.xml

이전 섹션의 코드 예제에서는 Thin Launcher (전제 조건 섹션에서 이미 살펴본 부팅 및 의존성 관리 플러그인 포함) 외에 Maven 플러그인을 선언했습니다.

이전에 보았던 Maven 사례와 마찬가지로 아티팩트는 애플리케이션의 의존성을 열거 하는 pom.xml 파일을 포함하고 사용하기 때문입니다 . 의 pom.xml 파일 호출 작업에 의해 생성되는 thinPom 어떤 항아리 작업의 암시 적 의존성이다.

생성 된 pom.xml 파일을 전용 작업으로 사용자 지정할 수 있습니다 . 여기서는 씬 플러그인이 이미 자동으로 수행하는 작업을 복제합니다.

task createPom {
    def basePath = 'build/resources/main/META-INF/maven'
    doLast {
        pom {
            withXml(dependencyManagement.pomConfigurer)
        }.writeTo("${basePath}/${project.group}/${project.name}/pom.xml")
    }
}

사용자 정의 pom.xml 파일 을 사용하기 위해 위의 작업을 jar 작업의 의존성에 추가합니다.

bootJar.dependsOn = [createPom]

4.5. Gradle 및 의존성 : thin.properties

우리는 또한 Gradle을이 생성 할 수 있습니다 thin.properties의 것이 아니라 파일 의 pom.xml을 , 우리가 메이븐과 함께 이전처럼.

생성하는 작업 thin.properties의 파일이라고 thinProperties를, 그리고 기본적으로 사용 아니에요. jar 작업의 의존성으로 추가 할 수 있습니다.

bootJar.dependsOn = [thinProperties]

5. 의존성 저장

얇은 jar의 요점은 의존성을 응용 프로그램과 번들로 묶지 않는 것입니다. 그러나 의존성은 마술처럼 사라지지 않고 단순히 다른 곳에 저장됩니다.

특히 Thin Launcher는 Maven 인프라를 사용하여 의존성을 해결하므로 다음과 같은 이점이 있습니다.

  1. 기본적으로 ~ / .m2 / repository에 있지만 다른 곳으로 이동할 수있는 로컬 Maven 저장소를 확인합니다 .
  2. 그런 다음 Maven Central (또는 기타 구성된 저장소에서 누락 된 의존성을 다운로드)합니다.
  3. 마지막으로 로컬 저장소에 캐시를 저장하므로 다음에 애플리케이션을 실행할 때 다시 다운로드 할 필요가 없습니다.

물론 다운로드 단계는 프로세스의 속도가 느리고 오류가 발생하기 쉬운 부분입니다 . 인터넷을 통해 Maven Central에 액세스하거나 로컬 프록시에 액세스해야하기 때문이며, 우리 모두 이러한 것들이 일반적으로 어떻게 신뢰할 수 없는지 알고 있습니다.

다행히도 애플리케이션과 함께 의존성을 배포하는 다양한 방법이 있습니다. 예를 들어 클라우드 배포를 위해 사전 패키지 된 컨테이너에 있습니다.

5.1. 워밍업을위한 애플리케이션 실행

의존성을 캐시하는 가장 간단한 방법은 대상 환경에서 애플리케이션의 워밍업 실행을 수행하는 것입니다. 앞서 살펴본 것처럼 이로 인해 의존성이 로컬 Maven 저장소에 다운로드되고 캐시됩니다. 둘 이상의 앱을 실행하면 저장소에 중복없이 모든 의존성이 포함됩니다.

응용 프로그램을 실행하면 원치 않는 부작용이 발생할 수 있으므로 사용자 코드를 실행하지 않고 의존성 만 확인하고 다운로드하는 "시험 실행"을 수행 할 수도 있습니다.

$ java -Dthin.dryrun=true -jar my-app-1.0.jar

Spring 부팅 규칙에 따라, 우리가 설정할 수로, 그 주 -Dthin.dryrun 로모그래퍼 또한 속성을 -thin.dryrun 응용 프로그램에 나와 명령 행 인수 THIN_DRYRUN의 시스템 속성입니다. false제외한 모든 값 은 Thin Launcher가 드라 이런을 수행하도록 지시합니다.

5.2. 빌드 중 의존성 패키징

또 다른 옵션은 JAR에 번들링하지 않고 빌드 중에 의존성을 수집하는 것입니다. 그런 다음 배포 절차의 일부로 대상 환경에 복사 할 수 있습니다.

대상 환경에서 애플리케이션을 실행할 필요가 없기 때문에 일반적으로 더 간단합니다. 그러나 여러 응용 프로그램을 배포하는 경우 수동으로 또는 스크립트를 사용하여 의존성을 병합해야합니다.

Maven 및 Gradle 용 Thin Plugin이 빌드 중에 의존성을 패키징하는 형식은 Maven 로컬 저장소와 동일합니다.

root/
    repository/
        com/
        net/
        org/
        ...

실제로 Thin Launcher를 사용하는 애플리케이션은 thin.root 속성을 사용하여 런타임에 이러한 디렉터리 (로컬 Maven 저장소 포함)를 가리킬 수 있습니다.

$ java -jar my-app-1.0.jar --thin.root=my-app/deps

또한 이러한 여러 디렉토리를 서로 복사하여 안전하게 병합 할 수 있으므로 필요한 모든 의존성이있는 Maven 저장소를 얻을 수 있습니다.

5.3. Maven으로 의존성 패키징

Maven이 의존성을 패키지 로 만들기 위해 spring-boot-thin-maven-plugin해결 목표를 사용합니다 . pom.xml 에서 수동 또는 자동으로 호출 할 수 있습니다 .

<plugin>
    <groupId>org.springframework.boot.experimental</groupId>
    <artifactId>spring-boot-thin-maven-plugin</artifactId>
    <version>${thin.version}</version>
    <executions>
        <execution>
        <!-- Download the dependencies at build time -->
        <id>resolve</id>
        <goals>
            <goal>resolve</goal>
        </goals>
        <inherited>false</inherited>
        </execution>
    </executions>
</plugin>

프로젝트를 빌드 한 후 이전 섹션에서 논의한 구조를 가진 target / thin / root / 디렉토리를 찾을 수 있습니다.

5.4. Gradle로 의존성 패키징

씬 런처 플러그인 과 함께 Gradle을 사용하는 경우 대신 thinResolve 작업을 사용할 수 있습니다. 이 작업은 이전 섹션의 Maven 플러그인과 유사하게 build / thin / root / 디렉토리 에 애플리케이션과 해당 의존성을 저장합니다 .

$ gradlew thinResolve

작성 당시 thin-launcher 플러그인에는 thin.properties 를 사용하는 경우 의존성이 저장되지 않도록하는 버그가 있습니다 . https://github.com/dsyer/spring-boot-thin-launcher/ 문제 / 53 .

6. 결론 및 추가 읽기

이 기사에서는 얇은 항아리를 만드는 방법을 살펴 보았습니다. 또한 Maven 인프라를 사용하여 의존성을 다운로드하고 저장하는 방법도 살펴 보았습니다.

씬 런처 홈페이지 에는 Heroku에 대한 클라우드 배포와 같은 시나리오에 대한 몇 가지 HOW-TO 사용방법(예제)와 지원되는 명령 줄 인수의 전체 List이 있습니다.

모든 Maven 예제 및 코드 스 니펫의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다 . Maven 프로젝트이므로 그대로 가져 와서 실행할 수 있어야합니다.

마찬가지로 모든 Gradle 예제는 이 GitHub 프로젝트를 참조합니다 .