>Java >java지도 시간 >다중 모듈 Gradle 프로젝트의 이동 경로 마이그레이션(클린 아키텍처)

다중 모듈 Gradle 프로젝트의 이동 경로 마이그레이션(클린 아키텍처)

Barbara Streisand
Barbara Streisand원래의
2025-01-19 08:05:08580검색

Flyway를 사용하여 Java에서 데이터베이스 마이그레이션 자동화

데이터베이스 마이그레이션은 특히 CI/CD(지속적인 통합 및 제공)가 표준 관행인 환경에서 소프트웨어 개발의 중요한 측면입니다. 애플리케이션이 성장하고 발전함에 따라 애플리케이션이 의존하는 데이터베이스 스키마도 마찬가지입니다. 이러한 스키마 변경 사항을 수동으로 관리하면 오류가 발생하고 상당한 시간이 소모될 수 있습니다.

데이터베이스 마이그레이션을 단순화하기 위해 맞춤화된 귀중한 오픈 소스 도구인 Flyway를 만나보세요. Flyway는 데이터베이스에 버전 제어를 도입하여 스키마를 안전하고 안정적으로 마이그레이션할 수 있도록 합니다. 이 기사에서는 Flyway를 사용하여 다중 모듈 Gragle Java 프로젝트에서 데이터베이스 마이그레이션을 자동화하여 데이터베이스 변경 관리가 간소화되고 오류 방지 프로세스가 되도록 하는 방법을 살펴보겠습니다.

이동경로에 대한 자세한 내용

Gradle의 다중 프로젝트 빌드 이해

일부 소규모 프로젝트나 모놀리식 애플리케이션은 하나의 빌드 파일과 통합 소스 구조로 관리할 수 있지만 대규모 프로젝트는 상호 의존적인 여러 모듈로 구성되는 경우가 많습니다. 여기서는 "상호의존적"이라는 용어가 핵심이며, 단일 빌드 프로세스를 통해 이러한 모듈을 연결해야 한다는 점을 강조합니다.

Gradle은 다중 모듈 프로젝트라고도 하는 다중 프로젝트 빌드 기능을 통해 이러한 설정을 충족합니다. Gradle 용어로는 이러한 모듈을 하위 프로젝트라고 합니다.

다중 프로젝트 빌드는 하나의 루트 프로젝트를 중심으로 구성되며 그 아래에 여러 하위 프로젝트를 포함할 수 있습니다.

gradle project

디렉터리 구조는 다음과 같아야 합니다.

├── .gradle
│   └── ⋮
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
├── gradlew
├── gradlew.bat
├── settings.gradle.kts (1)
├── sub-project-1
│   └── build.gradle.kts (2) 
├── sub-project-2
│   └── build.gradle.kts (2) 
└── sub-project-3
    └── build.gradle.kts (2)

(1) settings.gradle.kts 파일에는 모든 하위 프로젝트가 포함되어야 합니다.
(2) 각 하위 프로젝트에는 자체 build.gradle.kts 파일이 있어야 합니다.

클린 아키텍처를 위한 Gradle 하위 모듈 활용

클린 아키텍처는 관심사 분리를 강조하여 소프트웨어를 더 쉽게 유지 관리하고 테스트할 수 있도록 하는 디자인 패턴입니다. 프로젝트에서 이 아키텍처를 구현하는 실용적인 방법 중 하나는 Gradle의 하위 모듈 구조를 사용하여 코드베이스를 구성하는 것입니다. Clean Architecture를 Gradle 하위 모듈과 정렬하는 방법은 다음과 같습니다.

클린 아키텍처 레이어:
핵심:

  • 비즈니스 로직, 도메인 모델, 애플리케이션 규칙이 포함되어 있습니다. 외부나 웹에 의존하지 않습니다.
  • 가능한 경우 프레임워크별 구현과 독립적이어야 합니다.

외부:

  • 데이터베이스 마이그레이션이나 타사 서비스 상호 작용과 같은 외부 작업이나 통합을 처리합니다.
  • 비즈니스 로직을 위해 Core에 의존할 수 있지만 웹에 의존해서는 안 됩니다.

웹:

  • REST API를 노출하고 HTTP 요청을 처리하는 진입점.
  • 비즈니스 로직은 Core에 의존하고 통합은 외부에 의존할 수 있습니다.
├── .gradle
│   └── ⋮
├── gradle
│   ├── libs.versions.toml
│   └── wrapper
├── gradlew
├── gradlew.bat
├── settings.gradle.kts (1)
├── sub-project-1
│   └── build.gradle.kts (2) 
├── sub-project-2
│   └── build.gradle.kts (2) 
└── sub-project-3
    └── build.gradle.kts (2)

1단계: Java 기반 Gradle 프로젝트를 생성하고 이름을 "SchoolStaff"로 지정합니다.

2단계: Spring Initializr로 이동하여 Web이라는 REST API 프로젝트를 생성합니다.

3단계: Java 기반 Gradle 프로젝트를 생성하고 이름을 External으로 지정합니다.

4단계: Java 기반 Gradle 프로젝트를 생성하고 이름을 Core로 지정합니다.

루트 build.gradle.kts

SchoolStaff/
├── Core/
│   ├── src/
│   │   └── main/
│   │       ├── java/         # Business logic and domain objects
│   │       └── resources/    # Core-specific resources (if any)
│   └── build.gradle.kts
├── External/
│   ├── src/
│   │   └── main/
│   │       ├── java/         # External integration code
│   │       └── resources/    # db/migration and other external resources
│   └── build.gradle.kts
├── Web/
│   ├── src/
│   │   └── main/
│   │       ├── java/         # REST controllers and entry-point logic
│   │       └── resources/    # Application-specific configuration
│   └── build.gradle.kts
├── build.gradle.kts          # Root Gradle build
└── settings.gradle.kts       # Project module settings

settings.gradle.kts

plugins {
    id("java")
}

allprojects {
    group = "school.staff"
    version = "1.0.0"

    repositories {
        mavenLocal()
        mavenCentral()
    }
}

subprojects {
    apply(plugin = "java")

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

    tasks.test {
        useJUnitPlatform()
    }
}

"웹" 프로젝트에 필요한 종속성

rootProject.name = "SchoolStaff"

include("Core", "External", "Web")

"Core" 프로젝트에 필요한 종속성

dependencies {
    implementation(project(":Core"))
    implementation(project(":External"))
}

"외부" 프로젝트에 대한 필수 종속성

dependencies {
    runtimeOnly(project(":External"))
}

우리는 Flyway 마이그레이션을 위해 다음 플러그인을 사용합니다:

import java.sql.DriverManager
import java.util.Properties
// Function to load properties based on the environment
fun loadProperties(env: String): Properties {
    val properties = Properties()
    val propsFile = file("../web/src/main/resources/application-$env.properties")

    if (propsFile.exists()) {
        propsFile.inputStream().use { properties.load(it) }
    } else {
        throw GradleException("Properties file for environment '$env' not found: ${propsFile.absolutePath}")
    }

    return properties
}
// Set the environment (default is 'dev' if no argument is passed)
val env = project.findProperty("env")?.toString() ?: "dev"

// Load properties for the chosen environment
val dbProps = loadProperties(env)
buildscript {
    dependencies {
        classpath("org.flywaydb:flyway-database-postgresql:11.1.0") // This is required for the flyway plugin to work on the migration, otherwise it will throw an error as No Database found
        classpath("org.postgresql:postgresql:42.7.4")
    }
}
plugins {
    id("java-library")
    id("org.flywaydb.flyway") version "11.0.1"
}

group = "school.staff"
version = "unspecified"

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-data-jpa:3.4.0")
    implementation("org.postgresql:postgresql:42.7.4")
    implementation("org.flywaydb:flyway-core:11.0.1")
    implementation("org.flywaydb:flyway-database-postgresql:11.0.1")
    implementation("org.flywaydb:flyway-gradle-plugin:11.0.1")

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

tasks.test {
    useJUnitPlatform()
}

// Task to create the database if it doesn't exist
tasks.register("createDatabase") {
    doLast {
        val dbUrl = dbProps["spring.datasource.url"] as String
        val dbUsername = dbProps["spring.datasource.username"] as String
        val dbPassword = dbProps["spring.datasource.password"] as String

        // Extract the base URL and database name
        val baseDbUrl = dbUrl.substringBeforeLast("/")+ "/"
        val dbName = dbUrl.substringAfterLast("/")

        // Connect to the PostgreSQL server (without the specific database)
        DriverManager.getConnection(baseDbUrl, dbUsername, dbPassword).use { connection ->
            val stmt = connection.createStatement()
            val resultSet = stmt.executeQuery("SELECT 1 FROM pg_database WHERE datname = '$dbName'")
            if (!resultSet.next()) {
                println("Database '$dbName' does not exist. Creating it...")
                stmt.executeUpdate("CREATE DATABASE \"$dbName\"")
                println("Database '$dbName' created successfully.")
            } else {
                println("Database '$dbName' already exists.")
            }
        }
    }
}

flyway {
    url = dbProps["spring.datasource.url"] as String
    user = dbProps["spring.datasource.username"] as String
    password = dbProps["spring.datasource.password"] as String
    locations = arrayOf("classpath:db/migration")
    baselineOnMigrate = true
}

 //Ensure classes are built before migration
tasks.named("flywayMigrate").configure {
    dependsOn(tasks.named("createDatabase"))
    dependsOn(tasks.named("classes"))
}

이 접근 방식은 제어되고 안정적인 마이그레이션을 보장하므로 프로덕션 환경에 매우 적합합니다. 애플리케이션을 시작할 때마다 자동으로 마이그레이션을 실행하는 대신 필요한 경우에만 마이그레이션을 실행하여 더 큰 유연성과 제어력을 제공합니다.

또한 Spring 애플리케이션의 application.properties 파일을 활용하여 데이터베이스 연결 및 자격 증명을 관리하고 있습니다. BaselineOnMigrate = true 설정은 초기 마이그레이션이 향후 마이그레이션의 기준으로 사용되도록 보장합니다.

 plugins {
    id("org.flywaydb.flyway") version "11.0.1"
}

JPA Buddy를 사용하여 외부 프로젝트의 resources/db/migration 디렉터리 내에 모든 마이그레이션 파일을 생성할 수 있습니다.

V1__Initial_Migration

flyway {
    url = dbProps["spring.datasource.url"] as String
    user = dbProps["spring.datasource.username"] as String
    password = dbProps["spring.datasource.password"] as String
    locations = arrayOf("classpath:db/migration")
    baselineOnMigrate = true
}

루트 프로젝트에서 다음 명령을 사용하여 Flyway 마이그레이션을 실행할 수 있습니다.

CREATE TABLE _user
(
    id                 UUID NOT NULL,
    created_by         UUID,
    created_date       TIMESTAMP WITH TIME ZONE,
    last_modified_by   UUID,
    last_modified_date TIMESTAMP WITH TIME ZONE,
    first_name         VARCHAR(255),
    last_name          VARCHAR(255),
    email              VARCHAR(255),
    password           VARCHAR(255),
    tenant_id          UUID,
    CONSTRAINT pk__user PRIMARY KEY (id)
);

이렇게 하면 모든 마이그레이션 파일이 데이터베이스에 적용됩니다.

결론

Gradle 다중 모듈 프로젝트 내에서 Flyway를 사용하여 데이터베이스 마이그레이션을 자동화하는 방법을 살펴보았습니다. 이는 CI/CD 환경에서 스키마 일관성을 유지하는 데 중요합니다.

또한 Gradle이 다중 프로젝트 빌드를 지원하고 복잡한 프로젝트를 관리 가능한 하위 프로젝트로 구성하고 각각 고유한 빌드 구성을 가지며 루트 빌드 스크립트 아래 통합되는 방법도 다루었습니다.

마지막으로 Clean Architecture를 Gradle 모듈과 정렬하여 프로젝트를 코어, 외부 및 웹 레이어로 구성하여 우려 사항과 종속성 관리를 깔끔하게 분리했습니다.

이러한 방식은 모듈성, 자동화, 유지 관리 가능성을 향상시켜 확장 가능하고 오류 없는 소프트웨어 개발을 위한 기반을 마련합니다.

위 내용은 다중 모듈 Gradle 프로젝트의 이동 경로 마이그레이션(클린 아키텍처)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.