문제 상황
Spring Boot 프로젝트를 실행 가능한 JAR로 패키징할 때, 프로젝트 내에 두 개 이상의 main 메서드가 포함된 경우 다음과 같은 오류가 발생할 수 있습니다:
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.5.3.RELEASE:repackage (default) on project myapp: Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.5.3.RELEASE:repackage failed: Unable to find a single main class from the following candidates [com.example.api.ApiMain, com.example.web.WebMain]
이 문제는 Spring Boot Maven Plugin이 단일 메인 클래스를 찾을 수 없을 때 발생합니다. 플러그인은 `public static void main(String[] args)` 시그니처를 가진 메서드를 자동으로 찾지만, 여러 개가 있으면 어떤 것을 사용해야 할지 결정할 수 없습니다.
해결 방법
방법 1: 플러그인 설정에 mainClass 지정 (권장)
가장 일반적인 해결책은 Maven 플러그인 설정에 메인 클래스를 명시적으로 지정하는 것입니다:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.0</version>
<configuration>
<mainClass>com.example.web.WebMain</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
Spring Boot Maven Plugin은 다양한 목표(goal)를 제공하며, 위 설정에서 사용한 `repackage` 목표는 JAR 또는 WAR 파일을 실행 가능하게 만듭니다. 이 목표는 매니페스트 파일을 재작성하며, Main-Class와 Start-Class 항목을 관리합니다.
방법 2: start-class 속성 설정 (특정 조건 필요)
POM 파일이 `spring-boot-starter-parent`를 상속받는 경우, `
<properties>
<start-class>com.example.web.WebMain</start-class>
</properties>
이 방법은 첫 번째 방법과 동일한 효과를 가지지만, POM이 특정 부모를 상속해야 한다는 제약이 있습니다.
방법 3: 불필요한 메인 클래스 제거
가장 간단한 해결책은 프로젝트에서 사용하지 않는 메인 클래스를 주석 처리하거나 제거하는 것입니다. Spring Boot 애플리케이션은 단일 진입점을 가져야 하므로, 실제로 실행할 클래스 외의 다른 메인 메서드는 제거하는 것이 좋습니다.
Spring Boot Maven Plugin의 repackage 목표
Spring Boot Maven Plugin의 `repackage` 목표는 기존 JAR 또는 아카이브를 재패키징하여 명령줄에서 `java -jar`로 실행할 수 있도록 만듭니다. 이 목표는 다음과 같은 작업을 수행합니다:
- 실행 가능한 JAR 또는 WAR 파일을 생성합니다.
- 기본 Maven 아티팩트를 `.original` 접미사로 변경하고 새로운 아티팩트를 생성합니다.
- 매니페스트 파일을 수정하여 Main-Class와 Start-Class를 설정합니다.
이 목표를 사용하면 `layout` 속성을 통해 다양한 패키징 옵션을 지정할 수 있습니다. 예를 들어, `layout=NONE`으로 설정하면 종속성이 포함된 일반 JAR(실행 불가능)를 생성합니다.