Spring Multi-Module 프로젝트를 사용하는 이유는 여러 가지가 있으며, 대규모 애플리케이션 개발 및 유지보수에 많은 이점을 제공합니다.
Spring Multi Module을 활용한 프로젝트를 만들어 보겠습니다. (상위 프로젝트 명: multimodule
)
해당 프로젝트에서는 API
를 구현할 module-api
모듈과 jpa
도메인과 DB 연결 설정을 위한 module-common
으로 나누어 진행하겠습니다.
멀티 모듈을 생성하기 위해서는 상위 프로젝트에서 Module을 생성하면 됩니다. 우선 프로젝트 구조를 다음과 같이 생성하겠습니다.
상위 프로젝트의 settings.gradle
에서 사용할 모듈의 이름을 포함해 줍니다.
settings.gradle
rootProject.name = 'multimodule'
include 'module-api'
include 'module-common'
다음으로 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
플러그인은 api
와 implementation
의 두 가지 요소를 명확히 구분합니다.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
옵션은 테스트 코드 체크하는 과정을 생략한다는 의미 이다.module-api
에서는 module-common
을 사용하기 위해서 build.gradle
에 module-common
모듈을 implementation
해야 한다.
implementation project(':module-common') // root project -> settings.gradle 에 선언한 값과 동일
module-api
에서 module-common
의 domain
과 repository
의 component scan이 필요하다. 현재, 구조상 module-api
가 module-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);
}
}
module-api
의 application.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
module-api
를 설정 이외는 database
연결을 위한 설정위와 같은 과정을 통해 module-api
와 module-common
을 생성하고 module-api
에서 module-common
을 사용하는 것을 실습해 볼 수 있습니다.