Multi Module

duckbill413·2024년 6월 1일
0

Spring boot

목록 보기
9/13
post-thumbnail

Multi Module

Spring 멀티 모듈 예제 Github

Spring Multi-Module 프로젝트를 사용하는 이유는 여러 가지가 있으며, 대규모 애플리케이션 개발 및 유지보수에 많은 이점을 제공합니다.

1. 코드 조직화 및 재사용성

  • 모듈화된 코드 구조: 각 모듈은 특정 기능이나 도메인에 집중하여 개발될 수 있습니다. 이를 통해 코드를 더 잘 조직화하고, 관련 없는 코드들 간의 의존성을 줄일 수 있습니다.
  • 재사용 가능성: 공통 모듈을 여러 다른 서비스나 애플리케이션에서 재사용할 수 있습니다. 예를 들어, 유틸리티 함수나 공통 라이브러리를 별도의 모듈로 만들어 여러 프로젝트에서 사용할 수 있습니다.

2. 독립적인 개발 및 배포

  • 개별 모듈의 독립적 개발: 각 모듈을 독립적으로 개발하고 테스트할 수 있어, 팀 내에서 동시에 여러 모듈을 개발하는 것이 용이합니다.
  • 독립적 배포: 모듈을 독립적으로 배포할 수 있어, 특정 모듈의 업데이트가 다른 모듈에 영향을 미치지 않습니다. 이를 통해 배포 과정에서의 리스크를 줄일 수 있습니다.

3. 빌드 시간 단축

  • 병렬 빌드: 각 모듈을 병렬로 빌드할 수 있어, 전체 프로젝트의 빌드 시간을 줄일 수 있습니다. 특히, 변경 사항이 적은 모듈만 재빌드함으로써 효율적인 빌드 프로세스를 유지할 수 있습니다.

4. 테스트 용이성

  • 모듈 단위 테스트: 각 모듈별로 독립적인 테스트를 수행할 수 있어, 테스트의 범위와 깊이를 증가시킬 수 있습니다. 이를 통해 더 안정적인 코드를 작성할 수 있습니다.
  • 통합 테스트: 개별 모듈 단위의 테스트 외에도, 모듈 간의 상호작용을 통합 테스트할 수 있어, 전체 시스템의 안정성을 검증할 수 있습니다.

5. 유지보수 용이성

  • 명확한 경계: 각 모듈의 역할과 책임이 명확히 구분되기 때문에, 문제 발생 시 문제의 범위를 빠르게 좁히고 해결할 수 있습니다.
  • 의존성 관리: 모듈 간의 의존성을 명확히 관리할 수 있어, 특정 모듈의 변경이 다른 모듈에 미치는 영향을 최소화할 수 있습니다.

6. 팀 협업 향상

  • 분리된 책임: 팀 내에서 각 모듈의 책임을 분리하여, 여러 팀이 동시에 다양한 모듈을 개발할 수 있습니다. 이를 통해 협업이 용이해지고, 병목 현상이 줄어듭니다.
  • 코드 리뷰 및 관리: 각 모듈 별로 코드 리뷰를 수행할 수 있어, 코드 품질을 향상시키고 관리하기가 더 수월해집니다.

예시

Spring Multi Module을 활용한 프로젝트를 만들어 보겠습니다. (상위 프로젝트 명: multimodule)

해당 프로젝트에서는 API를 구현할 module-api 모듈과 jpa 도메인과 DB 연결 설정을 위한 module-common으로 나누어 진행하겠습니다.

  1. 멀티 모듈을 생성하기 위해서는 상위 프로젝트에서 Module을 생성하면 됩니다. 우선 프로젝트 구조를 다음과 같이 생성하겠습니다.

  2. 상위 프로젝트의 settings.gradle에서 사용할 모듈의 이름을 포함해 줍니다.

    settings.gradle

    rootProject.name = 'multimodule'
    
    include 'module-api'
    include 'module-common'
  3. 다음으로 module-common 모듈의 build.gradle에서 프로젝트에 사용될 dependency를 설정해 줍니다. 또한, tasks 설정을 해줍니다.

    plugins {
        id 'java'
        id 'org.springframework.boot' version '2.7.2'
        id 'io.spring.dependency-management' version '1.1.5'
        id 'java-library' // api 선언을 위해서 필요
    }
    
    group = 'dev.be'
    version = '0.0.1-SNAPSHOT'
    
    java {
        sourceCompatibility = '11'
    }
    
    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    
        api 'org.springframework.boot:spring-boot-starter-data-jpa'
        implementation 'mysql:mysql-connector-java'
    }
    
    tasks.named('test') {
        useJUnitPlatform()
    }
    
    tasks.bootJar { enabled = false } // default: true
    tasks.jar { enabled = true } // default: true
    • java-library plugin: java-library 플러그인은 apiimplementation의 두 가지 요소를 명확히 구분합니다.
      • api로 선언된 의존성은 소비자의 compile classpath와 runtime classpath를 모두 포함.
      • implementation 은 내부에서 사용된는 의존성을 선언하는데 사용됩니다. 즉, implementation 을 사용하여 선언된 의존성은 해당 모듈 내부에서만 사용되고, 다른 모듈에서 노출되지 않는다. 모듈 내부의 implementation 으로 선언된 라이브러리의 변경 사항은 다른 모듈에 영향을 주지 않는다.
    • tasks.bootJar: default: true common module은 실행 가능한 jar 파일을 생성할 필요가 없기 때문에 false로 변경
    • tasks.jar: default: true default 값이 true이지만 명시적으로 설정
      • xxx.jar: 일반적인 프로젝트 실행을 위한 jar파일
      • xxx-plain.jar: plain으로 생성된 jar 파일은 dependency를 가지지 않는다. 즉, 클래스와 리소스만을 포함한다. 따라서 서버를 실행 시킬 수 없다.
    • 프로젝트 빌드
      • ./gradlew clean :module-api:buildNeeded --stacktrace --info --refresh-dependencies -x test
        • 여기서 -x test 옵션은 테스트 코드 체크하는 과정을 생략한다는 의미 이다.
  4. module-api에서는 module-common을 사용하기 위해서 build.gradlemodule-common 모듈을 implementation 해야 한다.

    implementation project(':module-common') // root project -> settings.gradle 에 선언한 값과 동일
  5. module-api 에서 module-commondomainrepository의 component scan이 필요하다. 현재, 구조상 module-apimodule-common의 상위 모듈이 아니므로 component scan을 통해서 의존성을 스캔하는 과정이 필요한 것이다. module-api의 기본 실행 클래스를 아래와 같이 수정한다.

    @SpringBootApplication(
            scanBasePackages = {"dev.be.moduleapi", "dev.be.modulecommon"} // module-cmmon의 base package 위치
    )
    @EntityScan("dev.be.modulecommon.domain") // module-common의 domain 위치
    @EnableJpaRepositories({"dev.be.modulecommon.repositories"}) // module-common의 repository 위치
    public class ModuleApiApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ModuleApiApplication.class, args);
        }
    
    }
  6. module-apiapplication.yml 설정

    spring:
      application:
        name: module-api
      datasource:
        url: jdbc:mysql://localhost:3306/multimodule
        username: ssafy
        password: ssafy
        driver-class-name: com.mysql.cj.jdbc.Driver
      jpa:
        database: mysql
        database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
        hibernate:
          ddl-auto: create
        properties:
          hibernate:
            format_sql: true
            show_sql: true
            use_sql_comments: true
            jdbc:
              time_zone: Asia/Seoul
    • name으로 module-api를 설정 이외는 database연결을 위한 설정
  7. 위와 같은 과정을 통해 module-apimodule-common을 생성하고 module-api에서 module-common을 사용하는 것을 실습해 볼 수 있습니다.

profile
같이 공부합시다~

0개의 댓글