Backend/Ktor

[Ktor] 의존성 주입 라이브러리 Koin 설정

mopil 2023. 7. 10. 16:20
반응형

Ktor에는 스프링과 다르게 기본적으로 의존성 주입을 지원해주지 않는다.

(경량 프레임워크라 그런가... 스프링이 무겁고 러닝커브가 높지만 참 많은 것을 지원해 주는 것 같다.)

 

여하튼 그래서 이번에는 Koin이라는 코틀린 의존성 주입 라이브러리를 통해서 의존성 주입을 설정해 보자.

 

소스코드

https://github.com/mopil/ktor-server

 

GitHub - mopil/ktor-server: HikariCP + MySQL + Exposed (DAO) + Koin

HikariCP + MySQL + Exposed (DAO) + Koin. Contribute to mopil/ktor-server development by creating an account on GitHub.

github.com

 

Koin

https://github.com/InsertKoinIO/koin

 

GitHub - InsertKoinIO/koin: Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform - GitHub - InsertKoinIO/koin: Koin - a pragmatic lightweight dependency injection framework for K...

github.com

(이름을 참 잘 지은 것 같다)

 

    implementation("io.insert-koin:koin-ktor:$koinVersion")
    implementation("io.insert-koin:koin-logger-slf4j:$koinVersion")

gradle에 다음을 추가해 주자. 버전은 가장 최신버전을 사용하면 된다. 

 

 

# 의존성 주입 설정

Koin을 사용하려면 우선 Ktor 어플리케이션에 install 함수를 통해서 적용해줘야 한다.

그전에 어떤 대상들을 의존성 주입으로 관리할지 먼저 module이라는 고차함수를 통해 지정한다.

val dependencyInjectionModule = module {
    single { UserService(get()) }
    single<UserRepository> { UserRepositoryImpl() }
    single { ProductService(get()) }
    single<ProductRepository> { ProductRepositoryImpl() }
}

fun Application.configureDependencyInjection() {
    install(Koin) {
        SLF4JLogger()
        modules(dependencyInjectionModule)
    }
}

(Application.module 고차함수에서 configureDependencyInjection 함수를 호출해주어야 등록되는 것을 잊지말자!)

 

Repository는 인터페이스로, 모두 구현체를 직접 명시하면 된다.

의존성 주입이 설정되지 않으면 아예 서버가 부트 업되지 않으므로 누락되는 것 없이 안전하게 설정할 수 있다.

 

스프링과는 별개로 서비스나 컴포넌트를 제작할 때마다 명시적으로 이렇게 모듈로 등록해야 하는 게 좀 불편하다. 

 

 

# 의존성 주입받아서 사용하기

클래스 레벨은 코프링의 생성자 주입과 동일하게 사용하면 된다.

class ProductService(
    private val productRepository: ProductRepository
) {
    suspend fun createProduct(request: CreateProductRequest): IdResponse {
        val product = productRepository.save(request)
        return product.id.value.toResponse()
    }
    suspend fun getAllProducts(request: GetProductRequest): PageResponse<GetProductResponse> {
        return productRepository.findAllByCondition(request)
    }
}

 

Ktor 라우터(컨트롤러)는 클래스가 아니라 확장함수로 정의되기 때문에 이런 식으로 inject() 함수를 통해 주입받아서 사용하면 된다.

 

fun Route.productRouter() {
    val productService: ProductService by inject()

    get(Uris.Product.GET_ALL_PRODUCTS) {
        val params = GetProductRequest(call.parameters)
        call.respond(productService.getAllProducts(params))
    }
}

 

반응형