JAR -> WAR로 배포파일 변경하기

간혹가다 프로젝트를 진행하면서 jar로 배포를 하려다가 war 파일을 톰캣에 올려서 배포하게 변경되는 경우가 생기기도 합니다.
그런 경우 프로젝트가 정말 작고, 시작한 지 얼마 안 된 경우라면 새로 프로젝트를 패키징 설정을 war로 해서 새로 만드는 방법도 있지만… 좋은 방법도 아니고 일정 이상 프로젝트를 진행해서 그러기 쉽지 않은 경우가 발생할 수 있습니다.

그럴 경우 jar 파일로 생성되게 만든 프로젝트를 war 파일을 생성하게 하는 방법에 대해서 알아봅시다.

추가로 스프링 부트 2.0.5 버전에서 진행 한 내용이며 실습 코드 자체는 아주 간단하게도 아래와 같이 우리에게 친숙한 hello world를 보여주는 웹 앱입니다.

성공_화면


일단 jar로 패키징 되게 프로젝트를 만들어 봅니다.

jar_프로젝트

일단 maven의 경우 pom.xml의 내용을 보시면 아래와 같이 packaging 의 내용에 jar 가 들어 있는 걸 확인할 수 있습니다.

<groupId>com.example</groupId>
<artifactId>maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

gradle의 경우 별다른 내용이 없습니다…

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

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

이 상태에서 프로젝트를 만든 다음 빌드를 해보면 당연하게도 xxx.jar 파일이 만들어집니다.

여기서 war 파일을 만드는 것은 아주 간단합니다. 메이븐의 경우

<groupId>com.example</groupId>
<artifactId>maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

packaging의 내용을 war로 바꿔주기만 하면 됩니다…….

gradle의 경우 build.gradle을 보면

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

war {
	baseName = 'gradle'
	version = '0.0.1'
}

apply plugin: 'war'로 플러그인을 추가하고 war{}에 필요한 내용을 채워 넣으면 됩니다.

그러면 새로 빌드를 하면 xxx.war가 생성이 됩니다. gradle의 경우 위와 같이 설정해주면 gradle-0.0.1.war같이 파일명과 버젼링을 해줄 것이라 예상하시겠지만, 그렇지 않으신 분들도 계실 겁니다… (특히 부트 2버젼 대가 아니시라면) 그에 대해서는 차후 소개해드리도록 하겠습니다 :)


자 그러면 war 파일도 만들어 봤으니 톰캣을 이용해 배포해 보겠습니다!

실패_화면

?!

여기서 멘붕에 빠지는 경우들이 있으신데… 특히 저 같은 경우 aws에 엘라스틱빈스톡의 톰캣 환경에서 배포를 하기 위해 jar에서 war로 변경했던지라, 스프링 내에 설정을 잘 못 만든 것인지 빈스톡 설정을 잘 못 한 건지 엄청난 멘붕에 빠졌었던 기억이 나는군요…. 결국 당시엔 새로 프로젝트를 만들었습니다..


ServletInitializer

스프링부트를 통해 만든 웹 애플리케이션의 경우 embeded 톰켓을 이용한다면 @SpringBootApplication을 구현한 클래스만 있으면 되지만, 따로 톰켓을 통해 배포하는 경우 SpringBootServletInitializer를 상속받은 클래스가 필요합니다.

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(DemoWarApplication.class);
    }

}

아주 혹시나 알려드리면 DemoWarApplication.class 부분은 본인의 @SpringBootApplication 구현체를 넣으시면 됩니다. (스프링부트 생성시 존재하는 클래스)

경로1

ServletInitializer 추가

경로2

위와 같이 ServletInitializer를 추가해 주시면 됩니다.(war 패키징 되는 프로젝트로 생성하면 처음 초기화 시 위와 같이 ServletInitializer도 같이 생성되는 걸 볼 수 있습니다.)

그러고서 다시 war 파일을 빌드 해주시고 톰캣을 통해 배포하시면

성공_화면

정상적으로 배포되신 것을 확인하실 수 있습니다.

한 줄로 요약하면 maven, gradle에 해당하는 설정 파일에 war 관련 내용을 추가 한 후에, SpringBootServletInitializer을 상속 한 ServletInitializer를 만들어 주시면 됩니다.


참고 자료 : Spring Boot에서 배포환경 나누기, Spring Boot 웹 애플리케이션을 WAR로 배포할 때 왜 SpringBootServletInitializer를 상속해야 하는걸까?

(SpringBootServletInitializer에 대해 보다 자세히 알고 싶으시다면 두 번째 참고 자료를 추천드립니다.)