Kotlin Spring + Mybatis + Mysql 샘플 데이터 토이프로젝트 -9 멀티모듈 적용

선종우·2024년 9월 2일
0

Spring 노트

목록 보기
9/10
  • 기존 프로젝트를 여러 모듈로 나눠보기로 하였다.
  • 복잡한 프로젝트는 아니므로 모듈은 크게 presentation, domain, external로 구분하였다.
-demo(root)
	- presentation
    - domain
    - external
  • setting.gradle.kts 설정
    • root 모듈 아래에 설정, 모듈 추가를 하면 기본적으로 intellij에서 설정해준다.
rootProject.name = "demo"
include("external")
include("presentation")
include("domain")
  • 루트모듈의 src 폴더는 사용하지 않으므로 삭제해도 된다
  • 현재는 root 모듈의 gradle파일은 사용하지 않으므로 삭제해도 된다
  • 핵심 비즈니스 로직은 domain 모듈에 모은다. repository모듈을 구현한 Mybatis 관련 클래스도 도메인 모듈에 넣었다. (헥사고날 아키텍처에서는 repositort의 구현체도 외부 모듈로 뺀다)
  • 프로젝트 구조는 아래와 같이 된다.
/domain
	/src
    	/main
        	/kotlin
            	/domain
                	/annotation
                    /auth
                    /common
                    /employee
            /resources
            	/mapper
                	employeeMapper.xml
                mybatis-config.xml
        /test
        build.gradle.kts
  • 도메인 모듈은 실행파일 형태로 만들어질 필요가 없으므로 gradle 설정은 아래와 같이 한다
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
    id("org.springframework.boot") version "3.3.2"
    id("io.spring.dependency-management") version "1.1.6"
    kotlin("jvm") version "2.0.10"
    kotlin("plugin.spring") version "2.0.10"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web") {
        exclude("org.springframework.boot:spring-boot-starter-tomcat")
    }

    testImplementation(platform("org.junit:junit-bom:5.10.0"))
    testImplementation("org.junit.jupiter:junit-jupiter")
}

tasks.test {
    useJUnitPlatform()
}

val jar: Jar by tasks
val bootJar: BootJar by tasks

bootJar.enabled = false - plain.jar만 생성된다
jar.enabled = true
  • 웹 컨트롤러 역할을 할 Presentation모듈은 domain 모듈에 의존한다
  • Springboot의 시작점은 이 모듈이 된다. 이때 스프링을 구동하게 되면 domain모듈에 있는 config나 bean을 읽지 못해 의존성 주입에 실패한다.
  • 따라서 아래와 같이 scan을 할 basePackage를 명시적으로 지정해준다.
@ConfigurationPropertiesScan(basePackages = ["demo", "domain"])
@SpringBootApplication(scanBasePackages = ["demo", "domain"])
@MapperScan(basePackages = ["domain.auth.repository.mapper", "domain.employee.repository.mapper"])
class DemoApplication

fun main(args: Array<String>) {
	runApplication<DemoApplication>(*args)
}
  • 이때 유의할 점은 mybatis의 @Mapper 애노테이션을 정상적으로 스캔하기 위해 @MapperScan을 사용해야 한다는 점이다. 또한 basePackage를 명시할 때 최상위 패키지가 아닌 해당 Mapper 클래스가 존재하는 패키지를 구체적으로 명시해줘야 한다.

  • gradle은 아래와 같이 설정한다

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.3.2"
    id("io.spring.dependency-management") version "1.1.6"
    kotlin("jvm") version "2.0.10"
    kotlin("plugin.spring") version "2.0.10"
}

group = "com.example"
version = "0.0.1-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencyManagement {
    imports {
        mavenBom("io.github.resilience4j:resilience4j-bom:2.1.0")
    }
}

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

val jwtVersion by extra { "0.11.5" }

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")

    implementation(project(":domain")) -- 도메인 모듈에 대한 의존성을 추가한다
    testImplementation(platform("org.junit:junit-bom:5.10.0"))
    testImplementation("org.junit.jupiter:junit-jupiter")
    testImplementation("org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3")
    implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("org.springframework.boot:spring-boot-starter-aop")
    implementation("io.jsonwebtoken:jjwt-api:$jwtVersion")

}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs += "-Xjsr305=strict"
        jvmTarget = "17"
    }
}
  • dependencies에서 domain 모듈에 대한 의존성을 추가한다.
  • presentation모듈은 resilience4j를 사용하지 않음에도 아래 코드를 추가하지 않으면 의존성 에러가 발생한다. 이 부분에 대한 해결책은 다음 글에서 알아보겠다.
dependencyManagement {
    imports {
        mavenBom("io.github.resilience4j:resilience4j-bom:2.1.0")
    }
}

0개의 댓글