1. 소개

이 예제에서는 mvn spring-boot:run 명령을 통해 Spring Boot 웹 애플리케이션을 시작하는 것과 java -jar 명령 을 통해 jar/war 패키지로 컴파일한 후 실행하는 것의 차이점을 살펴보겠습니다 .

이 사용방법(예제)의 목적을 위해 Spring Boot 리패키지 목표 의 구성에 익숙하다고 가정합니다 . 이 항목에 대한 자세한 내용은 Spring Boot로 Fat Jar 앱 만들기를 참조하세요 .

2. Spring Boot Maven 플러그인

Spring Boot 애플리케이션을 작성할 때 Spring Boot Maven 플러그인은 코드를 빌드, 테스트 및 패키징하는 데 권장되는 도구입니다.

이 플러그인은 다음과 같은 편리한 기능을 많이 제공합니다.

  • 올바른 의존성 버전을 해결합니다.
  • 모든 의존성(필요한 경우 임베디드 애플리케이션 서버 포함)을 하나의 실행 가능한 팻 jar/war로 패키징할 수 있으며 다음도 수행합니다.
    • 클래스 경로 구성을 관리하여 java -jar 명령 에서 -cp 옵션을 건너뛸 수 있습니다.
    • 이제 패키지 내부에 중첩된 모든 외부 jar 라이브러리를 찾아 로드하기 위해 사용자 정의 ClassLoader를 구현합니다.
    • 자동으로 main() 메서드를 찾고 매니페스트에서 구성하므로 java -jar 명령 에서 기본 클래스를 지정할 필요가 없습니다.

3. 분해된 형태로 Maven으로 코드 실행하기

웹 애플리케이션에서 작업할 때 Spring Boot Maven 플러그인의 또 다른 매우 흥미로운 기능을 활용할 수 있습니다. 바로 임베디드 애플리케이션 서버에 웹 애플리케이션을 자동으로 배포하는 기능입니다.

Tomcat을 사용하여 코드를 실행하고 싶다는 것을 플러그인에 알리려면 하나의 의존성만 필요합니다.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency>

이제 프로젝트 루트 폴더에서 mvn spring-boot:run 명령을 실행할 때 플러그인은 pom 구성을 읽고 웹 애플리케이션 컨테이너가 필요하다는 것을 이해합니다.

mvn spring-boot:run 명령을 실행하면  Apache Tomcat 다운로드가 트리거되고 Tomcat 시작이 초기화됩니다.

$ mvn spring-boot:run
...
...
[INFO] --------------------< com.baeldung:spring-boot-ops >--------------------
[INFO] Building spring-boot-ops 0.0.1-SNAPSHOT
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.1.3.RELEASE:run (default-cli) > test-compile @ spring-boot-ops >>>
Downloading from central: https://repo.maven.apache.org/maven2/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.pom
Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.pom (1.8 kB at 2.8 kB/s)
...
...
[INFO] --- spring-boot-maven-plugin:2.1.3.RELEASE:run (default-cli) @ spring-boot-ops ---
...
...
11:33:36.648 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
11:33:36.649 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.16]
...
...
11:33:36.952 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
...
...
11:33:48.223 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
11:33:48.289 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
11:33:48.292 [main] INFO  org.baeldung.boot.Application - Started Application in 22.454 seconds (JVM running for 37.692)

로그에 'Started Application'이 포함된 줄이 표시되면 브라우저 주소 http://localhost:8080/에서 웹 애플리케이션을 쿼리할 준비가 된 것입니다.

4. 코드를 독립 실행형 패키지 애플리케이션으로 실행

개발 단계를 통과하고 애플리케이션을 프로덕션으로 가져오는 과정이 진행되면 애플리케이션을 패키징해야 합니다.

안타깝게도 jar 패키지 로 작업하는 경우 기본 Maven 패키지 목표에는 외부 의존성이 포함되지 않습니다. 이는 더 큰 프로젝트에서 라이브러리로만 사용할 수 있음을 의미합니다.

이 제한을 피하려면 Maven Spring Boot 플러그인 리패키지 목표를 활용하여 jar/war를 독립 실행형 애플리케이션으로 실행 해야 합니다 .

4.1. 구성

일반적으로 빌드 플러그인만 구성하면 됩니다.

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

예제 프로젝트에는 둘 이상의 기본 클래스가 포함되어 있으므로 플러그인을 구성하여 실행할 클래스를 Java에 알려야 합니다.

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.baeldung.webjar.WebjarsdemoApplication</mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>

또는 시작 클래스 속성 설정 :

<properties>
    <start-class>com.baeldung.webjar.WebjarsdemoApplication</start-class>
</properties>

4.2. 애플리케이션 실행

이제 두 가지 간단한 명령으로 예제 전쟁을 실행할 수 있습니다.

$ mvn clean package spring-boot:repackage
$ java -jar target/spring-boot-ops.war

jar 파일을 실행하는 방법에 대한 자세한 내용은 Run JAR Application With Command Line Arguments 문서에서 확인할 수 있습니다 .

4.3. 전쟁 파일 내부

위에서 언급한 명령이 전체 서버 애플리케이션을 실행하는 방법을 더 잘 이해하기 위해 spring-boot-ops.war를 살펴볼 수 있습니다 .

압축을 풀고 내부를 들여다보면 일반적인 용의자를 찾을 수 있습니다.

  • META-INF , 자동 생성된  MANIFEST.MF 포함
  • 컴파일된 클래스를 포함하는 WEB-INF/classes
  • WEB-INF/lib , 우리의 전쟁 의존성 및 포함된 Tomcat jar 파일을 보유합니다.

팻 패키지 구성과 관련된 일부 폴더가 있기 때문에 이것이 전부는 아닙니다.

  •  WEB-INF/lib-provided , 포함 실행 시 필요하지만 배포 시 필요하지 않은 외부 라이브러리 포함
  • org/springframework/boot/loader - Spring Boot 사용자 정의 클래스 로더를 보유합니다. 이 라이브러리는 외부 의존성을 로드하고 런타임에 액세스할 수 있도록 합니다.

4.4. 전쟁 선언문 내부

앞서 언급했듯이 Maven Spring Boot 플러그인은 메인 클래스를 찾아 java 명령 을 실행하는 데 필요한 구성을 생성합니다 .

결과 MANIFEST.MF에는 몇 가지 추가 줄이 있습니다.

Start-Class: com.baeldung.webjar.WebjarsdemoApplication
Main-Class: org.springframework.boot.loader.WarLauncher

특히 마지막 항목은 사용할 Spring Boot 클래스 로더 실행기를 지정하는 것을 볼 수 있습니다.

4.5. Jar 파일 내부

기본 패키징 전략으로 인해 우리의 전쟁 패키징 시나리오는 Spring Boot Maven Plugin을 사용하든 사용하지 않든 크게 다르지 않습니다 .

플러그인의 장점을 더 잘 이해하기 위해 pom 패키징 구성을 jar 로 변경하고 mvn clean 패키지를 다시 실행해 볼 수 있습니다 .

이제 fat jar가 이전 war 파일과 약간 다르게 구성되어 있음을 관찰할 수 있습니다.

  • 모든 클래스 및 리소스 폴더는 이제 BOOT-INF/classes 아래에 있습니다 .
  • BOOT-INF/lib는 모든 외부 라이브러리를 보유합니다.

플러그인이 없으면 lib 폴더가 존재하지 않으며 BOOT-INF/classes 의 모든 콘텐츠는 패키지의 루트에 위치합니다.

4.6. Jar 매니페스트 내부

매니페스트 . MF도 변경되어 다음과 같은 추가 라인이 있습니다.

Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.1.3.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher

Spring-Boot-ClassesSpring-Boot-Lib는 클래스 로더가 클래스와 외부 라이브러리를 찾을 위치를 알려주므로 특히 흥미롭습니다.

5. 선택 방법

도구를 분석할 때 이러한 도구가 만들어진 목적을 반드시 고려해야 합니다. 개발을 쉽게 하고 싶습니까, 아니면 원활한 배포 및 이식성을 보장하고 싶습니까? 이 선택에 의해 가장 영향을 받는 단계를 살펴보겠습니다.

5.1. 개발

개발자로서 우리는 코드를 로컬에서 실행하기 위해 환경을 설정하는 데 많은 시간을 할애할 필요 없이 대부분의 시간을 코딩하는 데 사용합니다. 간단한 응용 프로그램에서는 일반적으로 문제가 되지 않습니다. 그러나 보다 복잡한 프로젝트의 경우 환경 변수를 설정하고 서버를 시작하고 데이터베이스를 채워야 할 수 있습니다.

애플리케이션을 실행하려고 할 때마다 올바른 환경을 구성하는 것은 특히 둘 이상의 서비스를 동시에 실행해야 하는 경우 매우 비실용적입니다.

Maven으로 코드를 실행하면 도움이 됩니다. 우리는 이미 전체 코드베이스를 로컬에서 체크아웃했기 때문에 pom 구성 및 리소스 파일을 활용할 수 있습니다. 환경 변수를 설정하고 메모리 내 데이터베이스를 생성하며 올바른 서버 버전을 다운로드하고 하나의 명령으로 애플리케이션을 배포할 수도 있습니다.

각 모듈마다 다른 변수와 서버 버전이 필요한 다중 모듈 코드베이스에서도 Maven 프로필을 통해 올바른 환경을 쉽게 실행할 수 있습니다.

5.2. 생산

우리가 생산으로 이동할수록 대화는 안정성과 Security으로 더 많이 이동합니다. 그렇기 때문에 개발 시스템에 사용되는 프로세스를 실제 고객이 있는 서버에 적용할 수 없습니다.

이 단계에서 Maven을 통해 코드를 실행하는 것은 여러 가지 이유로 나쁜 습관입니다.

  • 우선 Maven을 설치해야 합니다.
  • 그런 다음 코드를 컴파일해야 하므로 전체 JDK(Java Development Kit)가 필요합니다.
  • 다음으로 코드베이스를 서버에 복사하고 모든 독점 코드를 일반 텍스트로 남겨 두어야 합니다.
  • mvn 명령은 수명 주기의 모든 단계(소스 찾기, 컴파일 및 실행)를 실행해야 합니다 .
  • 이전 포인트 덕분에 CPU도 낭비하고 클라우드 서버의 경우 돈도 낭비합니다.
  • Maven은 각각 메모리를 사용하는 여러 Java 프로세스를 생성합니다(기본적으로 각 프로세스는 상위 프로세스와 동일한 메모리 양을 사용함).
  • 마지막으로 배포할 서버가 여러 개인 경우 위의 모든 작업이 각 서버에서 반복됩니다.

이것들은 응용 프로그램을 패키지로 배송하는 것이 생산에 더 실용적인 몇 가지 이유입니다 .

6. 결론

이 기사에서는 Maven을 통해 코드를 실행하는 것과 java -jar 명령 을 통해 코드를 실행하는 것의 차이점을 살펴보았습니다 . 또한 몇 가지 실제 사례 시나리오에 대한 간략한 개요도 살펴보았습니다.

이 기사에서 사용된 소스 코드는 GitHub에서 사용할 수 있습니다 .

res – Maven (eBook) (cat=Maven)