Search
🤔

RuntimeOnly, CompileOnly, Api, Implementation

Created time
2024/04/15 07:42
Tags
SpringBoot
프로젝트

개요

아래와 같은 형식으로 api 모듈에서 :storage 모듈을 runtimeOnly 로, :domain 모듈을 implemenation으로 참조하고 있었는데, @SpringBootApplication 을 실행하면 :storage 모듈의 코드를 전혀 참조하지 못하는 에러가 발생하였습니다.
@SpringBootApplication class CoApplication fun main(args: Array<String>) { runApplication<CoApplication>(*args) }
Kotlin
복사
/** * build.gradle.kts */ dependencies { runtimeOnly(project(":storage:core-mysql")) implementation(project(":domain")) implementation("org.springframework.boot:spring-boot-starter-web") }
Groovy
복사
INFO 63377 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 6 ms. Found 0 JPA repository interfaces.
Kotlin
복사
곰곰히 생각해보면, runtimeOnly 로 참조하는 모듈의 경우, 스프링 어플리케이션이 실행될 때 컴파일 과정에 포함되지 않는 것이 당연합니다. 실행 시에만 필요하지, 컴파일 시 필요한 라이브러리는 아니니까요. 따라서 먼저 모듈을 빌드 후 실행했을 때 문제 없이 스프링부트 어플리케이션이 실행됨을 확인할 수 있었습니다.
INFO 66686 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 26 ms. Found 2 JPA repository interfaces.
Kotlin
복사

Gradle Dependencies

쉽게 정리하면 다음과 같다.
compileOnly : 컴파일 할 때만 사용
runtimeOnly : 런타임 할 때만 사용(컴파일 필요X)
annotationProcessor : lombok과 같은 어노테이션 라이브러리 사용
implementation : 컴파일 + 런타임
api : 컴파일 + 런타임 + 다른 라이브러리에서 해당 라이브러리 의존 시(a → b→ c) 추가 의존(a→c)

Storage 모듈을 runtimeOnly로 사용하는 이유

api 모듈은 accountRepository 를 도메인 모듈에서부터 참조하지만, storage 모듈에 구현되어 있는 db 접근 코드는 전혀 알지 못합니다.
@Service class AccountServiceImpl( private val accountRepository: AccountRepository ): AccountService { override fun getByEmail(email: String): Account { TODO("Not yet implemented") } } interface AccountRepository { fun getById(id: Long): Optional<Account> }
Kotlin
복사
이러한 이점을 얻을 수 있는 이유는, 스프링 어플리케이션이 실행될 때, 런타임 온리로 작성되어있는 스토리지 모듈의 레포지토리 빈을 AccountRepository 라는 추상화된 인터페이스에 자동으로 주입하기 때문입니다.
때문에 DI를 통해 각 모듈별로 역할이 완전히 분리되기 때문에, 로컬 환경에서 개발 후 Main 어플리케이션 실행 시 바로 작동하지 않을 수 있다는 귀찮음이 있음에도 runtimeOnly 로 데이터 접근 로직을 참조합니다.

References