Kotlin - 코틀린에 대해 (2)
목차
코틀린의 언어적인 장치를 스프링이 지원하는 법
스코프 함수(Scope functions)
환경 변수를 호출하는 코드가 있다고 예시를 들어 보겠습니다.
@SpringBootConfiguration
class config...
@Bean
fun dataSource(enviroment: Enviroment): DataSource {
val builder = EmbeddedDatabaseBuilder()
builder.setType(type)
...
builder.setScriptEncoding(encoding)
return builder.build()
}
자바에서는 빌더패턴을 사용한 코드가 자주 사용되어집니다. 하지만 코틀린에서는 조금 더 간결한 문법으로 코드의 가독성을 높이는 몇가지 방법이 있습니다. 지금 보여드릴 코드는 스코프 함수를 사용한 예제입니다.
@Bean
fun dataSource(enviroment: Enviroment): DataSource {
return EmbeddedDatabaseBuilder().apply {
setType(type)
...
setScriptEncoding(encoding)
}.build()
이 스코프 함수는 코틀린 표준 라이브러리에 포함된 기능으로 특정 객체의 컨텍스트내에서 동작하는 코드블럭을 실행한다고 보면 됩니다. 스코프 함수를 람다함수로 작성할 경우 임시스코프를 형성하게 되며 스코프 내에는 객체의 이름을 일일히 참조하지 않아도 객체를 제어할 수 있으며 it 과 같이 선언, 약속된 키워드를 통해 객체에 접근할 수도 있습니다.
확장함수(Extension functions)
스프링이 코틀린을 통해 제공하는 확장함수라는 것을 통해서 편하고 안전하게 환경변수를 꺼내는 등 확장함수를 사용할 수 있으며 총 세가지 형태의 확장함수를 지원합니다.
예를 들어 환경변수를 호출해야하는 경우 스프링에서는 PropertyResolver를 확장해서 몇가지 편의 기능을 코틀린의 확장 함수로 제공합니다.
val scripts = enviroment.getProperty<Array<String>>("sciprts")
// --->
inline fun <reified T> PropertyResolver.getProperty(key: String) : T? =
getProperty(key, T::class.java)
생성자 주입 constructor
테스트 코드를 작성할 때 보통 다양한 의존성 주입을 통해 테스트를 원활히 진행하도록 하고 있습니다.
코틀린은 이 의존성 주입 코드들을 간결하게 하기위해 @TestConstructor 어노테이션을 제공합니다.
@TestConstructor(autowireMode = AutowireMode.ALL) // 모든 의존성을 autowired 등록
internal class ChatControllerTests(val mockMvc: MockMvc) {
...
}
MockMvc DSL
MockMvc Test 를 작성할 때 보통 메소드체이닝 방식으로 하다보니 코드의 가독성이 떨어지는 경우가 있습니다. 코틀린은 이 역시 간결하게 작성하도록 도와주어 가독성을 높일 수 있습니다.
mockMvc.perform(
get("/forum/topics").accept(MediaType.TEXT_HTML)
).andExpect(
status.isOk
).andExpect(
view().name("forum/topics")
).andExpect(
model().attributeExists("topics")
)
Mockito → MockK DSL
이 코드를 스프링이 지원하는 MockMvc DSL 을 사용하면
mockMvc.get("/forum/topics") {
accept = MediaType.TEXT_HTML
}.andExpect {
status { isOk() }
view { name("forum/topics") }
model { attributeExists("topics") }
이렇게 간결한 코드로 바꿔서 코드의 가독성을 높일 수 있습니다.
코틀린과 스프링 - 비동기
스프링 3.2버전부터 지원되는 비동기 요청 처리가 있고, 스프링 5부터는 리액티브 타입(Mono, Flux)도 지원합니다. 그리고 현재 코틀린으로 비동기 요청처리는 스프링 웹플럭스에서 코루틴을 적극적으로 수용하려고 하고 있습니다.
기존 Webflux + 코틀린으로 구성된 코드 예제입니다.
@RestController
@RequestMapping("/notification")
class NotificationController(val forumNewsPublisher: ForumNewsPublisher) {
@GetMapping("/subscribe/news")
fun subscribeNews() : Mono<NewsDto> {
return forumNewsPublisher.subscribeReactive(
Duration.ofSeconds(5)
).flatMap { news ->
Mono.just(
NewsDto.of(news)
)
}
}
}
그리고 이 코드를 코루틴으로 비동기 처리로 변경한 동일한 기능의 코드입니다.
@RestController
@RequestMapping("/notification")
class NotificationController(val forumNewsPublisher: ForumNewsPublisher) {
@GetMapping("/subscribe/news")
suspend fun subscribeNews(): NewsDto {
return NewsDto.of(
forumNewsPublisher.subscribe(Duration.ofSeconds(5))
)
}
}