- 비동기 프로그래밍의 callback hell 을 해결
- kotlin 언어 키워드가 아닌 라이브러리로 존재
- js의 async/await 처럼 언어 자체의 특징이 아님
- Client: Asynchronous UI (ex. Android)
- Server: 여러 API를 동시에 호출
- blocking client 인
RestTemplate
을 쓸 경우에는 여러개의 코루틴을 만들어 멀티 스레드에 각각 배정하는 형태로 활용 가능
- non-blocking client 인
WebClient
를 쓸 경우에는 하나의 스레드에서도 여러개의 API 를 동시에 호출해서 전체 API 성능 향상 가능
- 아예 비동기 non-blocking framework 인
WebFlux
에도 활용할 수 있음
- 동시성 테스트에서도 활용할 수 있음
import kotlinx.coroutines.*
import org.springframework.web.client.RestTemplate
fun main() = runBlocking {
val restTemplate = RestTemplate()
// 여러 코루틴을 생성하여 멀티 스레드에 배정
val job1 = async(Dispatchers.IO) { callApi(restTemplate, "https://api.example.com/endpoint1") }
val job2 = async(Dispatchers.IO) { callApi(restTemplate, "https://api.example.com/endpoint2") }
// API 호출 결과를 동시에 기다림
val result1 = job1.await()
val result2 = job2.await()
println("Result1: $result1")
println("Result2: $result2")
}
suspend fun callApi(restTemplate: RestTemplate, url: String): String {
return restTemplate.getForObject(url, String::class.java) ?: "No response"
}
import kotlinx.coroutines.*
import org.springframework.web.reactive.function.client.WebClient
fun main() = runBlocking {
val webClient = WebClient.create()
// 여러 API 호출을 동시에 실행
val job1 = async { callApi(webClient, "https://api.example.com/endpoint1") }
val job2 = async { callApi(webClient, "https://api.example.com/endpoint2") }
// API 호출 결과를 동시에 기다림
val result1 = job1.await()
val result2 = job2.await()
println("Result1: $result1")
println("Result2: $result2")
}
suspend fun callApi(webClient: WebClient, url: String): String {
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(String::class.java)
.awaitFirst() // Coroutine을 사용하여 결과를 기다림
}
// implementation 'org.springframework.boot:spring-boot-starter-webflux'
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-reactor'
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
@Service
class ApiService(private val webClient: WebClient) {
suspend fun fetchParallelData(): List<String> = coroutineScope {
val api1 = async { callApi("https://api.example.com/endpoint1") }
val api2 = async { callApi("https://api.example.com/endpoint2") }
val result1 = api1.await()
val result2 = api2.await()
listOf(result1, result2)
}
private suspend fun callApi(url: String): String {
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(String::class.java)
.awaitSingle()
}
}
import kotlinx.coroutines.reactor.mono
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api")
class ApiController(private val apiService: ApiService) {
@GetMapping("/parallel")
fun getParallelData() = mono {
apiService.fetchParallelData()
}
}
import kotlinx.coroutines.*
import org.springframework.web.reactive.function.client.WebClient
fun main() = runBlocking {
val webClient = WebClient.create()
val urls = listOf(
"https://api.example.com/endpoint1",
"https://api.example.com/endpoint2",
"https://api.example.com/endpoint3"
)
// 동시성 테스트를 위해 여러 API 호출을 동시에 실행
val jobs = urls.map { url ->
async { callApi(webClient, url) }
}
// API 호출 결과를 동시에 기다림
val results = jobs.awaitAll()
results.forEachIndexed { index, result ->
println("Result${index + 1}: $result")
}
}
suspend fun callApi(webClient: WebClient, url: String): String {
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(String::class.java)
.awaitFirst() // Coroutine을 사용하여 결과를 기다림
}