๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โ˜˜๏ธ ๋ฐฑ์—”๋“œ: Backend

[Spring] ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ ์ ์šฉ

by ๐Ÿค ์ค€์ฝฉ์ด 2023. 6. 26.

๐Ÿ˜Ž ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์„ ๋„์ž…ํ•œ ์ด์œ 

 

๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ์ ์šฉ ์ „

 

์œ„ ์ด๋ฏธ์ง€๋Š” ์ง„ํ–‰์ค‘์ธ ํ•˜์šฐ์Šค ํ”„๋กœ์ ํŠธ์—์„œ ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์„ ์ ์šฉํ•˜๊ธฐ ์ „์˜ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

๊ธฐ์กด์—๋Š” ์„œ๋น„์Šค์˜ ๋ชจ๋“  ์ฝ”๋“œ๋“ค์ด ๋‹จ์ผ ๋ชจ๋“ˆ์— ํฌํ•จ๋œ ์ƒํƒœ์˜€์Šต๋‹ˆ๋‹ค.

 

ํ•˜์šฐ์Šค ํ”„๋กœ์ ํŠธ๋Š” ํ‘ธ์‹œ ์•Œ๋ฆผ ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ์ „์†กํ•˜๋Š” ์„œ๋ฒ„๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์šฐ์Šค ์„œ๋ฒ„ → ํ•˜์šฐ์Šค API ์„œ๋ฒ„, ํ•˜์šฐ์Šค ์•Œ๋ฆผ ์„œ๋ฒ„

 

์ด ๋•Œ, API ์„œ๋ฒ„์™€ ์•Œ๋ฆผ ์„œ๋ฒ„ ๋ชจ๋‘ domain ํŒจํ‚ค์ง€์˜ ์ฝ”๋“œ, external.client ํŒจํ‚ค์ง€์˜ ์ฝ”๋“œ, common ํŒจํ‚ค์ง€์˜ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์œ ์ง€ ๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ๋ฐ”๋ผ๋ดค์„ ๋•Œ, ์„œ๋ฒ„๊ฐ€ ๋‘˜๋กœ ๋ถ„๋ฆฌ๋˜๋ฉด์„œ ๊ณตํ†ต๋œ ํŒจํ‚ค์ง€์˜ ๋‚ด์šฉ์ด ์ˆ˜์ •๋˜๋ฉด ๋งค๋ฒˆ API ์„œ๋ฒ„์™€ ์•Œ๋ฆผ ์„œ๋ฒ„์˜ ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ์ˆ˜์ •ํ•ด์ค˜์•ผ ํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๋ถˆํŽธํ•จ์„ ํ•ด์†Œํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ์•ˆ์œผ๋กœ ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ๋„์ž…์„ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿคฉ

 

 

๐Ÿค” ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์ด๋ž€?

 

๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์€ ํ•˜๋‚˜์˜ ์‹œ์Šคํ…œ์ด๋‚˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ๋ชจ๋“ˆ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๋ชจ๋“ˆํ™”๋œ ๊ตฌ์กฐ๋Š” ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ฃผ๋Š”๋ฐ, ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ๋ชจ๋“ˆ์„ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์—์„œ๋„ ์žฌ์‚ฌ์šฉํ•ด์„œ ๊ฐœ๋ฐœ ์‹œ๊ฐ„๊ณผ ๋…ธ๋ ฅ์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ์ ์šฉ ํ›„

 

์œ„ ์ด๋ฏธ์ง€๋Š” ๋‹จ์ผ ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑ๋˜์—ˆ๋˜ ํ•˜์šฐ์Šค ํ”„๋กœ์ ํŠธ์— ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ์ ์šฉ์„ ์™„๋ฃŒํ•œ ๋ชจ์Šต์ž…๋‹ˆ๋‹ค.

์ „์ฒด ์ฝ”๋“œ๋Š” ๊นƒํ—ˆ๋ธŒ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

API ์„œ๋ฒ„(hous-api)์™€ ์•Œ๋ฆผ ์„œ๋ฒ„(hous-notification)์—์„œ ๊ณตํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ถ€๋ถ„์„ hous-common, hous-core, hous-external ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๊ตฌ์„ฑ์„ ํ•œ ๋•๋ถ„์—, ๊ณตํ†ต๋œ ๋ถ€๋ถ„์—์„œ ์ˆ˜์ •์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•ด๋„ ๋ถ„๋ฆฌํ•œ ๋ชจ๋“ˆ์—์„œ ํ•œ ๋ฒˆ๋งŒ ์ˆ˜์ •์„ ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€ ๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ๋” ๊ฐ„ํŽธํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

 

 

๐Ÿ‘ป ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ์ ์šฉ ๋ฐฉ๋ฒ•

 

์ด์ œ ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋“ค์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

 

๐Ÿ”ฎ ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ ์ถ”๊ฐ€

 

 

๋จผ์ € ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” ์ตœ์ƒ๋‹จ ํ”„๋กœ์ ํŠธ์—์„œ ๋งˆ์šฐ์Šค ์šฐํด๋ฆญ์„ ํ•˜๊ณ  New > Module ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

์ดํ›„ ๋ชจ๋“ˆ ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ  ์ƒ์„ฑํ•˜๋ฉด ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ์ด ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

 

settings.gradle

 

๋ชจ๋“ˆ์ด ์ƒ์„ฑ๋˜๋ฉด settings.gradle ํŒŒ์ผ์— ์ž๋™์œผ๋กœ ์ƒˆ๋กœ์šด ๋ชจ๋“ˆ์ด include ๋ฉ๋‹ˆ๋‹ค.

์ด๋Š” ์ƒˆ๋กœ์šด ํด๋”๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ง์ ‘ include ํ•ด์ค˜๋„ ๋ชจ๋“ˆ๋กœ ์ธ์‹๋œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.

 

 

๐Ÿ”ฎ build.gradle ์„ค์ •

 

๋‹ค์Œ์€ build.gradle ์„ ์„ค์ •ํ•  ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค.

์šฐ์„  ์ตœ์ƒ๋‹จ ํ”„๋กœ์ ํŠธ์˜ build.gradle ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

 

// server/build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
}

plugins {
    id "org.springframework.boot" version "2.7.1"
    id "io.spring.dependency-management" version "1.0.11.RELEASE"
    id "java"
}

// ํ•˜์œ„ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ ๊ณตํ†ต ์„ธํŒ…
subprojects {
    apply plugin: "org.springframework.boot"
    apply plugin: "io.spring.dependency-management"
    apply plugin: "java"

    group = "hous"
    version = "1.0.7-SNAPSHOT"
    sourceCompatibility = "11"

    repositories {
        mavenCentral()
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    dependencies {
        compileOnly "org.projectlombok:lombok"
        annotationProcessor "org.projectlombok:lombok"
        testCompileOnly("org.projectlombok:lombok")
        testAnnotationProcessor("org.projectlombok:lombok")
        testImplementation("org.springframework.boot:spring-boot-starter-test") {
            exclude group: "org.junit.vintage", module: "junit-vintage-engine"
        }
    }

    dependencyManagement {
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:2021.0.5"
        }
    }

    tasks.named("test") {
        useJUnitPlatform()
    }
}

 

๋‹จ์ผ ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ์˜ build.gradle ํŒŒ์ผ๊ณผ ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด๋ฉด subprojects ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

subprojects ์—๋Š” setting.gradle ์— include ๋œ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์— ๊ณตํ†ต์ ์œผ๋กœ ์ ์šฉํ•  ์„ค์ •์„ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ํ•˜์œ„ ํ”„๋กœ์ ํŠธ๋“ค์˜ build.gradle ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋จผ์ € ๊ณตํ†ต๋œ ๋ถ€๋ถ„์ธ hous-common, hous-core, hous-external ์˜ build.gradle ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

 

// server/hous-common/build.gradle

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

dependencies {
    ...
}

// server/hous-core/build.gradle

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

dependencies {
    implementation project(":hous-common")
    ...
}

// server/hous-external/build.gradle

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

dependencies {
    implementation project(":hous-common")
    ...
}

 

๋‹ค์Œ์€ API ์„œ๋ฒ„(hous-api)์™€ ์•Œ๋ฆผ ์„œ๋ฒ„(hous-notification)์˜ build.gradle ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

 

// server/hous-api/build.gradle

dependencies {
    implementation project(":hous-core")
    implementation project(":hous-common")
    implementation project(":hous-external")
		...
}

// server/hous-notification/build.gradle

dependencies {
    implementation project(":hous-core")
    implementation project(":hous-common")
    implementation project(":hous-external")
		...
}

 

๊ณตํ†ต๋œ ๋ชจ๋“ˆ์˜ build.gradle ๋‚ด์šฉ์„ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ถ€๋ถ„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

  • bootJar { enabled = false } : Spring Boot๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ bootJar ํƒœ์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ JAR ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์„ false ๋กœ ์„ค์ •ํ•˜๋ฉด, ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ค‘์— ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ JAR ํŒŒ์ผ์ด ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • jar { enabled = true } : ์ผ๋ฐ˜์ ์ธ Java ํ”„๋กœ์ ํŠธ์—์„œ ์ƒ์„ฑ๋˜๋Š” JAR ํŒŒ์ผ์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ์„ค์ •์ž…๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์„ true ๋กœ ์„ค์ •ํ•˜๋ฉด, ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ค‘์— ์ผ๋ฐ˜์ ์ธ JAR ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ด JAR ํŒŒ์ผ์€ ํ”„๋กœ์ ํŠธ์˜ ์ปดํŒŒ์ผ๋œ ํด๋ž˜์Šค ํŒŒ์ผ ๋ฐ ๋ฆฌ์†Œ์Šค ํŒŒ์ผ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

 

๊ณตํ†ต๋œ ๋ถ€๋ถ„์ธ hous-common, hous-core, hous-external ๋ชจ๋“ˆ๋“ค์€ ๊ฐœ๋ณ„์ ์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๊ณ , API ์„œ๋ฒ„์™€ ์•Œ๋ฆผ ์„œ๋ฒ„์— ํฌํ•จ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์€ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋กœ ๋ชจ๋“ˆ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • implementation project(":some-module") : ์˜์กด์„ฑ ๊ด€๋ฆฌ๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ด ์„ค์ •์€ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ๊ฐ€ some-module ํ”„๋กœ์ ํŠธ์— ์˜์กดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

 

โ—๏ธ ์ฃผ์˜ํ•  ์ 

๋ชจ๋“ˆ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์„ค์ •ํ•  ๋•Œ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด,
hous-core ๋ชจ๋“ˆ์—์„œ hous-common ์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ,
hous-common ๋ชจ๋“ˆ์—์„œ hous-core ์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค!

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ์„ ์„ค๊ณ„ํ•  ๋•Œ, ๊ฐ ๋ชจ๋“ˆ์˜ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ  ์˜์กด์„ฑ ๊ตฌ์กฐ๋ฅผ ์ฃผ์˜ํ•ด์„œ ์„ค๊ณ„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

๐Ÿ”ฎ Component Scan ํŒจํ‚ค์ง€ ๋“ฑ๋ก

 

ํ˜„์žฌ API ์„œ๋ฒ„์™€, ์•Œ๋ฆผ ์„œ๋ฒ„์—์„œ๋Š” hous-common, hous-core, hous-external ๋ชจ๋“ˆ์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ๋ณ„๋‹ค๋ฅธ ์„ค์ •์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด Spring ์€ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์— ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์„ Bean ์œผ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

 

@SpringBootApplication(scanBasePackages = {"hous.core", "hous.common", "hous.external", "hous.api"})
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}
}

 

์œ„์™€ ๊ฐ™์ด scanBasePackages ์— ํŒจํ‚ค์ง€ ์ด๋ฆ„๋“ค์„ ์ž…๋ ฅํ•ด์ค˜์„œ Component Scan ์‹œ์— ์Šค์บ”ํ•  ํŒจํ‚ค์ง€๋ฅผ ์ง€์ •ํ•ด์•ผ Spring ์ด ์ •์ƒ์ ์œผ๋กœ ๋ชจ๋“  Bean ๋“ค์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

 

๐Ÿ‘ป ๋ฉ€ํ‹ฐ ๋ชจ๋“ˆ ๋นŒ๋“œ ๋ฐฉ๋ฒ•

 

API ์„œ๋ฒ„์™€ ์•Œ๋ฆผ ์„œ๋ฒ„๋ฅผ ๋นŒ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

# API ์„œ๋ฒ„
./gradlew hous-api:bootJar

# ์•Œ๋ฆผ ์„œ๋ฒ„
./gradlew hous-notification:bootJar