모종닷컴

멀티 모듈 프로젝트에서는 아카이브 이름도 조심해야 합니다. 본문

Programming/Spring

멀티 모듈 프로젝트에서는 아카이브 이름도 조심해야 합니다.

모종 2022. 9. 24. 01:21
반응형

오늘은 정말 간단한 글 하나를 올려보려고 합니다. 내용은 멀티 모듈 프로젝트에서 모듈의 겹치는 이름으로 인해 겪은 삽질기입니다. 상황을 재현해보기 간단하게 세팅을 먼저 해보도록 하겠습니다.

프로젝트 구조

  • 프로젝트는 projectA, projectB 두 개로 만들어져 있습니다.
  • projectA는 app, domain 모듈을 지니고 있고, projectB는 domain 모듈만 지니고 있습니다.

projectA 빌드스크립트

  • war 관련 파일 설정이 추가되어있습니다.
apply plugin: 'war'

bootWar {
    mainClassName = "com.example.projectA.app.MainAppKt" // 코틀린 파일이 자바로 해석되면서 클래스명 뒤에 'Kt'가 붙는다
    archiveName("${project.name}.war")
}

dependencies {
    implementation project(":projectA:app")
}

subprojects {
    bootJar.enabled = false
    jar.enabled = true
}

project(":projectA:domain") {

}
project(":projectA:app") {
    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        implementation project(":projectA:domain")
        implementation project(":projectB:domain")
    }
}

 

Project-a:domain 모듈

@Component
class Coffee { val name = "coffee" }

 

Project-a:app 모듈

  • 패키지 스캔에 주의
@SpringBootApplication(scanBasePackages = ["com.example.projectA.domain", "com.example.projectB.domain", "com.example.projectA.app"])
class MainApp

fun main(args: Array<String>) {
    runApplication<MainApp>(*args)
}

@Component
class ReadyEventHandler(
    val coffee: Coffee,
    val donut: Donut
): CommandLineRunner {
    override fun run(vararg args: String) {
        println(coffee.name)
        println(donut.name)
    }
}

projectB 빌드 스크립트

 

 

project(":projectB:domain") {
    dependencies {
        implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    }
}
allprojects {
    bootJar.enabled = false
    jar.enabled = true
}

 

Project-b:domain 모듈

@Component
class Donut { val name = "donut" }

 

실행 결과

 

WAR를 실행

gradle build를 하거나 bootWar 태스크를 통해 war 파일을 만들고 해당 파일을 실행시켜보도록 하겠습니다. 저는 bootWar를 실행시켰고, 그 결과 아래 사진과 같은 경로에서 war 파일이 생성되었음을 알 수 있습니다.

그럼 이제 이 WAR를 실행시켜보겠습니다. 명령어는 java -jar projectA.jar입니다.

실행을 시키면 오류가 좀 길게 나올 텐데 주된 원인은 아래 사진과 같이 클래스를 찾을 수 없다입니다.

왜 클래스가 없다는 걸까 하고 war 파일의 압축을 풀어보았습니다. 그랬더니 굉장히 이상한 점이 있었습니다. projectA와 projectB의 domain 모듈을 의존하고 있는데 그 두 개의 파일 이름이 똑같다는 것이었습니다. 따라서 WAR를 만드는 과정에서 이름이 domain.jar인 파일이 두 개가 생성되었고, 그중 한 개가 덮어 쓰이는 바람에 클래스 정보가 없다고 하게 된 것이죠.. 

해결

해결법은 너무 간단합니다. jar 파일을 만들 때 네이밍 규칙을 정해주는 겁니다. jar.enabled = true 부분을 아래처럼 수정해주게 된다면 {부모 프로젝트의 이름}-{모듈 이름}. jar와 같은 형식으로 jar 파일이 만들어지게 됩니다. 예를 들면 projectA-domain.jar , projectB-domain.jar 와 같은 식으로요

jar {
    archiveName("${parent.name}-${project.name}.jar")
    setEnabled(true)
}

다음과 같은 방식으로 파일 이름을 정해주고 다시 bootWar로 생성 및 압축을 풀어보겠습니다. 그러면 아래 사진과 같이 정상적으로 domain.jar가 두 개가 보입니다.

다시 실행

그렇다면 이제 war를 다시 한번 실행해보도록 하겠습니다. 이제는 정상적으로 뜨고 있는 모습을 볼 수 있습니다.

 

반응형