반응형

multi-module-root

~/settings.gradle.kts

rootProject.name = "multi-module-root"

include(
    "common:core",
    "common:calculator",
    "bootstrap:demo-api",
)

~/build.gradle.kts

plugins {
    kotlin("jvm") version "1.9.24"
    kotlin("plugin.spring") version "1.9.24"
    id("org.springframework.boot") version "3.3.1"
    id("io.spring.dependency-management") version "1.1.5"
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

kotlin {
    compilerOptions {
        freeCompilerArgs.addAll("-Xjsr305=strict")
    }
}

allprojects {
    group = "com.multi.module.demo"
    version = "0.0.1-SNAPSHOT"

    tasks.withType<Test> {
        useJUnitPlatform()
    }

    repositories {
        mavenCentral()
    }
}

subprojects {
    apply(plugin = "org.springframework.boot")
    apply(plugin = "io.spring.dependency-management")
    apply(plugin = "org.jetbrains.kotlin.plugin.spring")
    apply(plugin = "kotlin")
    apply(plugin = "kotlin-kapt")

    dependencies {
        implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
        implementation("org.jetbrains.kotlin:kotlin-reflect")
        testImplementation("org.springframework.boot:spring-boot-starter-test")
        testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
        testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    }
}

common/core

~/common/core/src/main/kotlin/com.multi.module.demo.core/YamlPropertySourceFactory.kt

class YamlPropertySourceFactory : PropertySourceFactory {
    override fun createPropertySource(name: String?, resource: EncodedResource): PropertySource<*> {
        val factory = YamlPropertiesFactoryBean()
        factory.setResources(resource.resource)
        return PropertiesPropertySource(resource.resource.filename!!, factory.`object`!!)
    }
}

common/calculator

~/common/calculator/build.gradle.kts

dependencies {
    implementation(project(":common:core"))
    implementation("org.springframework:spring-context")
}

~/common/calculator/src/main/resources/calculator.yml

demo:
  value2: value2

~/common/calculator/src/main/kotlin/com.multi.module.demo.common/CalculatorConfig.kt

// 아래처럼 application.yml이 아닌 별도의 설명 파일명으로 지정해줘야 사용하는 모듈에서 설정값이 병합된다.
@PropertySource(
    value = ["classpath:calculator.yml"],
    factory = YamlPropertySourceFactory::class,
)
@Configuration
class CalculatorConfig

~/common/calculator/src/main/kotlin/com.multi.module.demo.common/AddCalculator.kt

@Component
class AddCalculator {
    fun add(a: Int, b: Int): Int {
        return a + b
    }
}

bootstrap/demo-api

~/bootstrap/demo-api/build.gradle.kts

dependencies {
    implementation(project(":common:calculator")) // common/calculator 모듈 추가
    implementation("org.springframework.boot:spring-boot-starter-web")
}

~/bootstrap/demo-api/src/main/resources/application.yml

server:
  port: 8081

demo:
  value1: value1

~/bootstrap/demo-api/src/main/kotlin/com.multi.module.demo.api.controller/DemoController.kt

@RestController
class DemoController(
    private val addCalculator: AddCalculator,
    @Value("\${demo.value1}") private val value1: String,
    @Value("\${demo.value2}") private val value2: String,
) {
    @GetMapping("/api/demo")
    fun demo(): Int {
        println("$value1 / $value2")
        return addCalculator.add(1, 2)
    }
}

~/bootstrap/demo-api/src/main/kotlin/com.multi.module.demo.api/Application.kt

// scan 필요한 모듈 패키지 경로 추가
@SpringBootApplication(
    scanBasePackages = [
        "com.multi.module.demo.api",
        "com.multi.module.demo.common",
    ],
)
class Application

fun main(args: Array<String>) {
    runApplication<Application>(*args)
}
반응형

'Development > Spring' 카테고리의 다른 글

[Spring] Circuit Breaker(with resilience4j)  (0) 2024.07.15
[Spring] Sharding  (0) 2024.07.12
[Spring] Exposed  (0) 2024.04.10
[Spring] HTTP Interface  (0) 2024.03.19
[Spring] Elasticsearch  (0) 2024.01.01

+ Recent posts