SlideShare a Scribd company logo
1 of 47
Kotlin Coroutines
& Spring Framework
Coupang Tech CoP
Catalog Platform & Quality tribe
debop@coupang.com
목차
• Why Kotlin?
• Coroutines
• Spring Asynchronous
• Spring with Coroutines
Why Kotlin?
Concise, Safe, Versatile, Interoperable, Tooling
Combines OO and functional features
Focused on
• Interoperability
• Safety
• Clarity
• Tooling support
a pragmatic programming language
for JVM, Android, JavaScript, LLVM
bytecode
Interoperability
Java
*.kt
*.java
compiler
Javacompiler
Concise
Drastically reduce
The amount of boilerplate code you need to write
data class Customer(val name: String,
var email: String,
val company: String = “coupang”)
Use lambda expression
val positiveNumbers = list.filter { it > 0 }
data class : POJO with getter,setter, equals, hashCode, toString, copy
Concise
Use lambda expression
val positiveNumbers = list.firstOrNull { it > 0 }
Lazy initialization
lateinit var positiveNumbers:List<Int>
val positiveNumbers by lazy { listOf(1,2,3) }
SAFE
All type is Nonnull is default
var output:String
output = null // compilation error
println(output.length())
user?.name?.isEmpty() ?: true
Rid NullPointerExceptions !!!
Auto-cast
fun calcuateTotal(obj:Any) {
if(obj is Invoice) {
obj.calculateTotal() // auto-cast
}
}
Versatile
• Android : No performance impact. Very small runtime.
• JavaScript: Write code in Kotlin and target JavaScript to run on Node.js or in
browser
• Web: Whether you want strongly typed HTML, CSS builder or just plain web
development
• Application Server
• The technology doesn’t matter. 100% compatible with all JVM frameworks.
• Enterpise
• Use Kotlin for any type of Enterprise Java EE development.
• Native
• Kotlin/Native is a LLVM backend for the Kotlin compiler, runtime implementation
and native code generation facility using LLVM toolchain.
Kotlin Basics
Let’s look at real code
Functions
fun sum(a: Int, b: Int): Int {
return a + b
}
fun sum(a: Int, b: Int) = a + b
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}
Variables
val a: Int = 1
val b = 1 // `Int` type is inferred
var c: Int // Type required when no initializer
// is provided
c = 1 // definite assignment
var x = 5 // `Int` type is inferred
x += 1
x ++
String Interpolation
val i = 10
val s = “i=$i” // evaluates to “i=10"
val s = “abc”
val str = “$s.length is ${s.length}”
// evaluates to “abc.length is 3"
val price = ""”
|${‘$’}9.99
""”.trimMargin()
When Expression
when (x) {
1 -> print(“x == 1”)
2 -> print(“x == 2”)
0, 1 -> print(“x == 0 or x == 1”)
parseInt(s) -> print(“s encodes x”)
in 1..10 -> print(”x is in the range”)
in validNumbers ->
!in 10..20 -> print(”x is not in the range”)
is String -> x.startsWith(“prefix”)
x.isOdd() -> print(“x is odd”)
x.isEven() -> print(“x is even”)
else -> println(“otherwise”)
}
Loop
for(item in collection)
print(item)
for(i in array.indices)
print(array[i])
for((index,value) in array.withIndex()) {
print(“element at $index is $value”)
}
Collections
val immutableList = listOf(1, 2, 3)
val mutable = mutableListOf(1, 2, 3)
val arrayList = arrayListOf(1, 2, 3)
val immutableMap = mapOf("foo" to 1, "bar" to 2)
val readWriteMap = hashMapOf("foo" to 1, "bar" to 2)
println(map["foo"])
Kotlin Avanced
Let’s look at real code
null safety
clean = cleaner?.javaClass?.getMethod("clean")
fun load(resourceBasename: String, rootPath: String? = null): Config {
val config = ConfigFactory.load(resourceBasename)
return rootPath?.let { path -> config.getConfig(path) } ?: config
}
Operators
operator fun Duration.unaryMinus(): Duration = this.negated()
operator fun Duration.div(divisor: Int): Duration = this.dividedBy(divisor.toLong())
operator fun Duration.div(divisor: Long): Duration = this.dividedBy(divisor)
operator fun Duration.times(multiplicand: Int): Duration = this.multipliedBy(multiplicand.toLong())
operator fun Duration.times(multiplicand: Long): Duration = this.multipliedBy(multiplicand)
operator fun ReadableInstant.rangeTo(other: ReadableInstant): Interval = Interval(this, other)
operator fun Instant.minus(builder: DurationBuilder): Instant = this.minus(builder.period.toStandardDuration())
operator fun Instant.plus(builder: DurationBuilder): Instant = this.plus(builder.period.toStandardDuration())
operator fun get(index: Int): ITimeLineMoment
operator fun set(index: Int, value:ITimeLineMoment): Unit
Extension Functions
fun String?.toUtf8Bytes(): ByteArray = this?.toByteArray(Charsets.UTF_8) ?: emptyByteArray
fun String?.toUtf8ByteBuffer(): ByteBuffer =
this?.let { Charsets.UTF_8.encode(this) } ?: ByteBuffer.allocate(0)
fun ByteArray?.toUtf8String(): String = this?.toString(Charsets.UTF_8) ?: EMPTY_STRING
fun ByteBuffer?.toUtf8String(): String =
this?.let { Charsets.UTF_8.decode(this).toString() } ?: EMPTY_STRING
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
Coroutines in Kotlin
Experimental features in Kotlin 1.1
kotlinx.coroutines
A Fiber is a lightweight thread that uses cooperative multitasking instead of preemptive
multitasking. A running fiber must explicitly "yield" to allow another fiber to run, which makes their
implementation much easier than kernel or user threads.
A Coroutine is a component that generalizes a subroutine to allow multiple entry points for
suspending and resuming execution at certain locations. Unlike subroutines, coroutines can
exit by calling other coroutines, which may later return to the point where they were invoked in the
original coroutine.
A Green Thread is a thread that is scheduled by a virtual machine (VM) instead of natively by the
underlying operating system. Green threads emulate multithreaded environments without relying on
any native OS capabilities, and they are managed in user space instead of kernel space, enabling
them to work in environments that do not have native thread support.
• Process: OS-managed (possibly) truly concurrent, at least in the presence of suitable hardware
support. Exist within their own address space.
• Thread: OS-managed, within the same address space as the parent and all its other threads.
Possibly truly concurrent, and multi-tasking is pre-emptive.
• Green Thread: These are user-space projections of the same concept as threads, but are not OS-
managed. Probably not truly concurrent, except in the sense that there may be multiple worker
threads or processes giving them CPU time concurrently, so probably best to consider this as
interleaved or multiplexed.
• Fibers: OS-managed. Exactly threads, except co-operatively multitasking, and hence not truly
concurrent.
• Coroutines: Exactly fibers, except not OS-managed.
• Goroutines: They claim to be unlike anything else, but they seem to be exactly green threads, as
in, process-managed in a single address space and multiplexed onto system threads. Perhaps
somebody with more knowledge of Go can cut through the marketing material.
이런 개념들을 알아야 …
async/await / yield
fibers
[stackless] continuations
Suspendable
Computations
public CompletionStage<Boolean> addAdultItemAsync(final long productId, final long itemId) {
log.trace("Add adult product cache. productId={}, itemId={}", productId, itemId);
final RLock lock = getProductLock(productId);
return lock.lockAsync(3000, TimeUnit.MILLISECONDS)
.thenComposeAsync(rl -> updateProductItemMapping(productId, itemId), global)
.thenComposeAsync(updated -> adultInverseIndex.fastPutAsync(itemId, productId), global)
.thenComposeAsync(added -> adultProductItemMap.putAsync(productId, itemId), global)
.whenCompleteAsync((result, error) -> lock.forceUnlock(), global);
}
Future combination is weired 😫
Suspendable Computation
asyncUI {
val image = await(loadImage(url))
myUI.setImage(image)
}
Suspending call Time consuming operation
UI Thread
await(…)
loadImage(url)
Worker Thread
setImage(…)
Continuation
Coroutines Goals
• Asynchronous programming (and more)
• without explicit callbacks
• without explicit Future combinators (see Deathwing code)
• Maximum flexibility for library designer
• with minimal runtime support
• and no macros (like Scala)
Coroutines 종류
Stackless Stackful
Language
restrictions
Use in special context 😫 Use anywhere 😀
Implemented in C#, Scala, Kotlin, … Quasar, Javaflow …
Code transformation Local (compiler magic) 😀 All over the place 😫
Runtime support Little 😀 Substantial 😫
The C# Way
async Task<String> work() {
Thread.sleep(200);
return “done”;
}
async Task moreWork() {
Console.WriteLine(“Work started”);
var str = await work();
Console.WriteLine($“Work completed: {str}”);
}
The Kotlin Way
fun work(): Deferred<String> = async(CommonPool) {
delay(200). // non-blocking Thread.sleep()
“done”
}
fun moreWork():Deferred<Unit> = async(CommonPool) {
println(“Work started”)
val str = await(work())
println(“Work completed: $str”)
}
How suspension works
fun moreWork():Deferred<Unit> =
async(CommonPool) {
println(“Work started”)
val str = await(work())
println(“Work completed: $str”)
}
controller.await(
work(),
current_continuation
)
return
Coroutines : Job
@Test fun `coroutine is light-weight`() = runBlocking {
val jobs = List(100_000) {
launch(CommonPool) {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Yield example : Lazy Fibonacci
val seq = buildSequence<Int> {
var a = 0
var b = 1
yield(1)
while (true) {
yield(a + b)
val tmp = a + b
a = b
b = tmp
}
}
val list = seq.take(10).toList()
assertThat(list).isEqualTo(listOf(1, 1, 2, 3, 5, 8, 13, 21, 34, 55))
Channel
@Test fun `channel basic`() = runBlocking {
val channel = Channel<Int>()
launch(CommonPool) {
(1 .. 5).forEach { channel.send(it * it) }
}
repeat(5) {
println(channel.receive())
}
println("Done!")
}
Async@Spring
SpringCamp 2017 참고
Spring Framework 비동기 방식
• @Async
• Async Request Processing
• Callable
• DeferedResult
• ResponseBodyEmitter
• AsyncRestTemplate
@Async
• SimpleAsyncTaskExecutor 를 이용하여, 지정한 작업을 수행
• Not ThreadPool !!!
• @Async 는 실전에서는 사용하지 말 것 !!!
Asychronous MVC 의 리턴 타입
• Callable<T>
• WebAsyncTask<T>
• DeferredResult<T>
• ListenableFuture<T>
• CompletionStage<T>
• ResponseBodyEmitter
@GetMapping("/composeasync2")
DeferredResult<String> asyncCompose2() {
DeferredResult dr = new DeferredResult();
ListenableFuture<String> f1 = myService.async();
f1.addCallback(res1 -> {
ListenableFuture<String> f2 = myService.async2(res1);
f2.addCallback(res2 -> {
ListenableFuture<String> f3 = myService.async3(res2);
f3.addCallback(res3 -> {
dr.setResult(res3);
}, e -> {
dr.setErrorResult(e);
});
}, e -> {
dr.setErrorResult(e);
});
}, e->{
dr.setErrorResult(e);
});
return dr;
}
알흠다운 콜백
헬
AsyncRestTemplate
• Spring 4.0 부터 RestTemplate 의 비동기-논블록킹 버전인
AsyncRestTemplate 제공
• 겉은 비동기-논블록킹이지만 논블록킹 IO 를 사용하지 않음 ㅠ.
ㅠ
• Netty 를 이용하여 논블록킹 IO (NioEventLoopEventGroup) 을
사용할 수 있음
• 리턴 타입이 ListenableFuture 라 콜백 헬 발생 !!!
 ListenableFuture 를 Kotlin Coroutines 의 Deferred 로 변환
가능
Async@Spring
• TaskExecutor 의 전략적 활용이 중요
• 스프링의 모든 비동기 기술에는 ExecutorService 의 세밀한 설정이 가
능
• CompletableFuture 도 ExecutorService의 설계가 중요
• 비동기 스프링 기술을 사용하는 이유?
• IO 가 많은 서버에서 서버 자원의 효율적 활용
Low Latency, High Throughput
• 서버 외부 작업
• 그럼 Spring 에서 다른 방법은 없나
• Callback Hell 은 못 피하는 것인가?
• Java 8 ForkJoin Pool 이나 Scala 의 Global Executor 을 쓰면 안되나?
•
Coroutines@Spring
Coroutines with Spring
• Kotlin suspend 함수를 Spring 에서 직접 이용
• Spring TaskExecutor 를 사용하지 않고, ForkJoin Pool 사용
• Callback Hell 없이 async/await 사용
• Spring 에서 Kotlin Coroutines 의 다양한 기능 활용
• Async IO
• Channel
Coroutines 을 사용하기 위한 Spring Configuration
@SpringBootApplication
@EnableAutoConfiguration
@EnableCoroutine
@EnableWebCoroutine
open class DemoAppConfiguration {
@Bean
fun demoService(): DemoService {
return DemoService()
}
}
open class DemoService {
@Scheduled(fixedRate = 60_000)
suspend open fun everyMinute() {
log.info { "I'm still alive ... every minutes I will back..." }
}
suspend open fun delayedReturn(str: String, delayMillis: Long): String {
delay(delayMillis)
return str
}
@Coroutine(COMMON_POOL)
suspend open fun commonPoolReturn(str: String, delayMillis: Long): String {
delay(delayMillis)
return str
}
}
Coroutines 가 적용된 RestController
@RestController
open class DemoController @Inject constructor(private val demoService: DemoService) {
private val restOperations = CoroutineRestOperations.invoke()
@GetMapping("/delayed")
suspend open fun delayedReturn(): String {
log.info { "Before call to [demoService.delayed]" }
val result = demoService.delayedReturn("delayed", 1000)
log.info { "After call to [demoService.delayed]" }
return result
}
@GetMapping("/commonPool")
suspend open fun commonPoolReturn(): String {
log.info { "Before call to [demoService.commonPoolReturn]" }
val result = demoService.commonPoolReturn("commonPool", 1000)
log.info { "After call to [demoService.commonPoolReturn]" }
return result
}
@GetMapping("/rest")
@Coroutine(COMMON_POOL)
suspend open fun rest(request: HttpServletRequest): String {
val result = restOperations.getForEntity(request.requestURL.toString()
.replace("rest", "delayed"),
String::class.java)
return "Rest result: ${result.body}"
}
RestTemplate 에서 Coroutine 이 적용된 CoroutineRestOperations 인터페이스를 사용하여,
외부 서버 정보를 요청할 수도 있다.  RestTemplate 처럼 Blocking 되지 않는다.
interface CoroutineRestOperations {
companion object : KLogging() {
operator fun invoke(restOperations: RestOperations = RestTemplate(),
context: CoroutineContext = NewThreadCoroutineDispatcher): CoroutineRestOperations {
log.info { "Create CoroutineRestOperations Proxy ..." }
return createCoroutineProxy(CoroutineRestOperations::class.java,
restOperations,
DefaultCoroutineProxyConfig(context))
}
}
}
suspend fun <T : Any?> getForEntity(url: String, responseType: Class<T>?, vararg uriVariables: Any?):
ResponseEntity<T>
Concolusion
• 범용의 Spring Framework 에 Kotlin Coroutines 을 사용
• Low latency, High throughput 실현
• 비동기, 논 블럭킹을 Readable Code 로 구현
• Java CompletableFuture 의 thenXXXX 메소드에서 해방
• Spring context 를 이용하여 향후 retry, scheduled 등 다양한
방식의 구현체에 Coroutines 적용 예정
• Effective Java 를 배워서 구현하려면, 차라리 Kotlin 으로 구현
해라
• 향후 Kotlin Native 로 진정한 비동기 IO 를 사용할 수 있다.
Thank you!

More Related Content

What's hot

M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
日本マイクロソフト株式会社
 
initとプロセス再起動
initとプロセス再起動initとプロセス再起動
initとプロセス再起動
Takashi Takizawa
 
M04_失敗しないための Azure Virtual Desktop 設計ガイド
M04_失敗しないための Azure Virtual Desktop 設計ガイドM04_失敗しないための Azure Virtual Desktop 設計ガイド
M04_失敗しないための Azure Virtual Desktop 設計ガイド
日本マイクロソフト株式会社
 

What's hot (20)

ID管理/認証システム導入の理想と現実
ID管理/認証システム導入の理想と現実ID管理/認証システム導入の理想と現実
ID管理/認証システム導入の理想と現実
 
V1.1 CD03 Azure Active Directory B2C/B2B コラボレーションによる Customer Identity and Ac...
V1.1 CD03 Azure Active Directory B2C/B2B コラボレーションによる Customer Identity and Ac...V1.1 CD03 Azure Active Directory B2C/B2B コラボレーションによる Customer Identity and Ac...
V1.1 CD03 Azure Active Directory B2C/B2B コラボレーションによる Customer Identity and Ac...
 
Grafana Dashboards as Code
Grafana Dashboards as CodeGrafana Dashboards as Code
Grafana Dashboards as Code
 
ID連携における仮名
ID連携における仮名ID連携における仮名
ID連携における仮名
 
無料で仮想Junos環境を手元に作ろう
無料で仮想Junos環境を手元に作ろう無料で仮想Junos環境を手元に作ろう
無料で仮想Junos環境を手元に作ろう
 
今日から始めるDigitalOcean
今日から始めるDigitalOcean今日から始めるDigitalOcean
今日から始めるDigitalOcean
 
M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
M17_情シス必見、Azure Arc によるマルチプラットフォーム管理の今 [Microsoft Japan Digital Days]
 
ニワトリでもわかるECS入門
ニワトリでもわかるECS入門ニワトリでもわかるECS入門
ニワトリでもわかるECS入門
 
3000社の業務データ絞り込みを支える技術
3000社の業務データ絞り込みを支える技術3000社の業務データ絞り込みを支える技術
3000社の業務データ絞り込みを支える技術
 
CentOS 8で標準搭載! 「389-ds」で構築する 認証サーバーについて
CentOS 8で標準搭載! 「389-ds」で構築する 認証サーバーについてCentOS 8で標準搭載! 「389-ds」で構築する 認証サーバーについて
CentOS 8で標準搭載! 「389-ds」で構築する 認証サーバーについて
 
ソフトウェア設計の学び方を考える
ソフトウェア設計の学び方を考えるソフトウェア設計の学び方を考える
ソフトウェア設計の学び方を考える
 
initとプロセス再起動
initとプロセス再起動initとプロセス再起動
initとプロセス再起動
 
CyberAgentのインフラについて メディア事業編 #catechchallenge
CyberAgentのインフラについて メディア事業編 #catechchallengeCyberAgentのインフラについて メディア事業編 #catechchallenge
CyberAgentのインフラについて メディア事業編 #catechchallenge
 
M04_失敗しないための Azure Virtual Desktop 設計ガイド
M04_失敗しないための Azure Virtual Desktop 設計ガイドM04_失敗しないための Azure Virtual Desktop 設計ガイド
M04_失敗しないための Azure Virtual Desktop 設計ガイド
 
KLabのインフラエンジニア 〜 こんな感じで働いてます 〜
KLabのインフラエンジニア 〜 こんな感じで働いてます 〜KLabのインフラエンジニア 〜 こんな感じで働いてます 〜
KLabのインフラエンジニア 〜 こんな感じで働いてます 〜
 
Azure Infrastructure as Code 体験入隊
Azure Infrastructure as Code 体験入隊Azure Infrastructure as Code 体験入隊
Azure Infrastructure as Code 体験入隊
 
リクルート流Elasticsearchの使い方
リクルート流Elasticsearchの使い方リクルート流Elasticsearchの使い方
リクルート流Elasticsearchの使い方
 
楽天サービスとインフラ部隊
楽天サービスとインフラ部隊楽天サービスとインフラ部隊
楽天サービスとインフラ部隊
 
Introducing of Ethereum Account Abstraction
Introducing of Ethereum Account AbstractionIntroducing of Ethereum Account Abstraction
Introducing of Ethereum Account Abstraction
 
40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること40歳過ぎてもエンジニアでいるためにやっていること
40歳過ぎてもエンジニアでいるためにやっていること
 

Similar to Kotlin coroutines and spring framework

An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
Adam Getchell
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
Yandex
 
Os Reindersfinal
Os ReindersfinalOs Reindersfinal
Os Reindersfinal
oscon2007
 
Os Reindersfinal
Os ReindersfinalOs Reindersfinal
Os Reindersfinal
oscon2007
 

Similar to Kotlin coroutines and spring framework (20)

The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard Library
 
An Overview Of Python With Functional Programming
An Overview Of Python With Functional ProgrammingAn Overview Of Python With Functional Programming
An Overview Of Python With Functional Programming
 
KotlinForJavaDevelopers-UJUG.pptx
KotlinForJavaDevelopers-UJUG.pptxKotlinForJavaDevelopers-UJUG.pptx
KotlinForJavaDevelopers-UJUG.pptx
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVMVoxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
Voxxed Days Vienna - The Why and How of Reactive Web-Applications on the JVM
 
Os Reindersfinal
Os ReindersfinalOs Reindersfinal
Os Reindersfinal
 
Os Reindersfinal
Os ReindersfinalOs Reindersfinal
Os Reindersfinal
 
Kotlin: A pragmatic language by JetBrains
Kotlin: A pragmatic language by JetBrainsKotlin: A pragmatic language by JetBrains
Kotlin: A pragmatic language by JetBrains
 
TypeScript Best Practices
TypeScript Best PracticesTypeScript Best Practices
TypeScript Best Practices
 
Effective Object Oriented Design in Cpp
Effective Object Oriented Design in CppEffective Object Oriented Design in Cpp
Effective Object Oriented Design in Cpp
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
C# - What's next
C# - What's nextC# - What's next
C# - What's next
 
Cocoa heads 09112017
Cocoa heads 09112017Cocoa heads 09112017
Cocoa heads 09112017
 
Java Tutorial
Java Tutorial Java Tutorial
Java Tutorial
 
Scala - brief intro
Scala - brief introScala - brief intro
Scala - brief intro
 
Android 101 - Building a simple app with Kotlin in 90 minutes
Android 101 - Building a simple app with Kotlin in 90 minutesAndroid 101 - Building a simple app with Kotlin in 90 minutes
Android 101 - Building a simple app with Kotlin in 90 minutes
 
Kotlin boost yourproductivity
Kotlin boost yourproductivityKotlin boost yourproductivity
Kotlin boost yourproductivity
 
Introduction to Scalding and Monoids
Introduction to Scalding and MonoidsIntroduction to Scalding and Monoids
Introduction to Scalding and Monoids
 
From Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risksFrom Java to Scala - advantages and possible risks
From Java to Scala - advantages and possible risks
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
 

More from Sunghyouk Bae

Multithread pattern 소개
Multithread pattern 소개Multithread pattern 소개
Multithread pattern 소개
Sunghyouk Bae
 

More from Sunghyouk Bae (16)

JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
 
Introduction of failsafe
Introduction of failsafeIntroduction of failsafe
Introduction of failsafe
 
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018Kotlin @ Coupang Backed - JetBrains Day seoul 2018
Kotlin @ Coupang Backed - JetBrains Day seoul 2018
 
Spring data requery
Spring data requerySpring data requery
Spring data requery
 
Requery overview
Requery overviewRequery overview
Requery overview
 
Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017Kotlin @ Coupang Backend 2017
Kotlin @ Coupang Backend 2017
 
measure metrics
measure metricsmeasure metrics
measure metrics
 
Alternatives of JPA/Hibernate
Alternatives of JPA/HibernateAlternatives of JPA/Hibernate
Alternatives of JPA/Hibernate
 
Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)Java naming strategy (자바 명명 전략)
Java naming strategy (자바 명명 전략)
 
테스트자동화와 TDD
테스트자동화와 TDD테스트자동화와 TDD
테스트자동화와 TDD
 
SpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSLSpringBoot with MyBatis, Flyway, QueryDSL
SpringBoot with MyBatis, Flyway, QueryDSL
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
 
좋은 개발자 되기
좋은 개발자 되기좋은 개발자 되기
좋은 개발자 되기
 
Using AdoRepository
Using AdoRepositoryUsing AdoRepository
Using AdoRepository
 
Multithread pattern 소개
Multithread pattern 소개Multithread pattern 소개
Multithread pattern 소개
 
Strategy Maps
Strategy MapsStrategy Maps
Strategy Maps
 

Recently uploaded

%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 

Recently uploaded (20)

WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 

Kotlin coroutines and spring framework

  • 1. Kotlin Coroutines & Spring Framework Coupang Tech CoP Catalog Platform & Quality tribe debop@coupang.com
  • 2. 목차 • Why Kotlin? • Coroutines • Spring Asynchronous • Spring with Coroutines
  • 3. Why Kotlin? Concise, Safe, Versatile, Interoperable, Tooling
  • 4. Combines OO and functional features Focused on • Interoperability • Safety • Clarity • Tooling support a pragmatic programming language for JVM, Android, JavaScript, LLVM
  • 7. Concise Drastically reduce The amount of boilerplate code you need to write data class Customer(val name: String, var email: String, val company: String = “coupang”) Use lambda expression val positiveNumbers = list.filter { it > 0 } data class : POJO with getter,setter, equals, hashCode, toString, copy
  • 8. Concise Use lambda expression val positiveNumbers = list.firstOrNull { it > 0 } Lazy initialization lateinit var positiveNumbers:List<Int> val positiveNumbers by lazy { listOf(1,2,3) }
  • 9. SAFE All type is Nonnull is default var output:String output = null // compilation error println(output.length()) user?.name?.isEmpty() ?: true Rid NullPointerExceptions !!! Auto-cast fun calcuateTotal(obj:Any) { if(obj is Invoice) { obj.calculateTotal() // auto-cast } }
  • 10. Versatile • Android : No performance impact. Very small runtime. • JavaScript: Write code in Kotlin and target JavaScript to run on Node.js or in browser • Web: Whether you want strongly typed HTML, CSS builder or just plain web development • Application Server • The technology doesn’t matter. 100% compatible with all JVM frameworks. • Enterpise • Use Kotlin for any type of Enterprise Java EE development. • Native • Kotlin/Native is a LLVM backend for the Kotlin compiler, runtime implementation and native code generation facility using LLVM toolchain.
  • 12. Functions fun sum(a: Int, b: Int): Int { return a + b } fun sum(a: Int, b: Int) = a + b fun printSum(a: Int, b: Int): Unit { print(a + b) } Variables val a: Int = 1 val b = 1 // `Int` type is inferred var c: Int // Type required when no initializer // is provided c = 1 // definite assignment var x = 5 // `Int` type is inferred x += 1 x ++
  • 13. String Interpolation val i = 10 val s = “i=$i” // evaluates to “i=10" val s = “abc” val str = “$s.length is ${s.length}” // evaluates to “abc.length is 3" val price = ""” |${‘$’}9.99 ""”.trimMargin() When Expression when (x) { 1 -> print(“x == 1”) 2 -> print(“x == 2”) 0, 1 -> print(“x == 0 or x == 1”) parseInt(s) -> print(“s encodes x”) in 1..10 -> print(”x is in the range”) in validNumbers -> !in 10..20 -> print(”x is not in the range”) is String -> x.startsWith(“prefix”) x.isOdd() -> print(“x is odd”) x.isEven() -> print(“x is even”) else -> println(“otherwise”) }
  • 14. Loop for(item in collection) print(item) for(i in array.indices) print(array[i]) for((index,value) in array.withIndex()) { print(“element at $index is $value”) } Collections val immutableList = listOf(1, 2, 3) val mutable = mutableListOf(1, 2, 3) val arrayList = arrayListOf(1, 2, 3) val immutableMap = mapOf("foo" to 1, "bar" to 2) val readWriteMap = hashMapOf("foo" to 1, "bar" to 2) println(map["foo"])
  • 16. null safety clean = cleaner?.javaClass?.getMethod("clean") fun load(resourceBasename: String, rootPath: String? = null): Config { val config = ConfigFactory.load(resourceBasename) return rootPath?.let { path -> config.getConfig(path) } ?: config }
  • 17. Operators operator fun Duration.unaryMinus(): Duration = this.negated() operator fun Duration.div(divisor: Int): Duration = this.dividedBy(divisor.toLong()) operator fun Duration.div(divisor: Long): Duration = this.dividedBy(divisor) operator fun Duration.times(multiplicand: Int): Duration = this.multipliedBy(multiplicand.toLong()) operator fun Duration.times(multiplicand: Long): Duration = this.multipliedBy(multiplicand) operator fun ReadableInstant.rangeTo(other: ReadableInstant): Interval = Interval(this, other) operator fun Instant.minus(builder: DurationBuilder): Instant = this.minus(builder.period.toStandardDuration()) operator fun Instant.plus(builder: DurationBuilder): Instant = this.plus(builder.period.toStandardDuration()) operator fun get(index: Int): ITimeLineMoment operator fun set(index: Int, value:ITimeLineMoment): Unit
  • 18. Extension Functions fun String?.toUtf8Bytes(): ByteArray = this?.toByteArray(Charsets.UTF_8) ?: emptyByteArray fun String?.toUtf8ByteBuffer(): ByteBuffer = this?.let { Charsets.UTF_8.encode(this) } ?: ByteBuffer.allocate(0) fun ByteArray?.toUtf8String(): String = this?.toString(Charsets.UTF_8) ?: EMPTY_STRING fun ByteBuffer?.toUtf8String(): String = this?.let { Charsets.UTF_8.decode(this).toString() } ?: EMPTY_STRING fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
  • 19. Coroutines in Kotlin Experimental features in Kotlin 1.1 kotlinx.coroutines
  • 20. A Fiber is a lightweight thread that uses cooperative multitasking instead of preemptive multitasking. A running fiber must explicitly "yield" to allow another fiber to run, which makes their implementation much easier than kernel or user threads. A Coroutine is a component that generalizes a subroutine to allow multiple entry points for suspending and resuming execution at certain locations. Unlike subroutines, coroutines can exit by calling other coroutines, which may later return to the point where they were invoked in the original coroutine. A Green Thread is a thread that is scheduled by a virtual machine (VM) instead of natively by the underlying operating system. Green threads emulate multithreaded environments without relying on any native OS capabilities, and they are managed in user space instead of kernel space, enabling them to work in environments that do not have native thread support.
  • 21. • Process: OS-managed (possibly) truly concurrent, at least in the presence of suitable hardware support. Exist within their own address space. • Thread: OS-managed, within the same address space as the parent and all its other threads. Possibly truly concurrent, and multi-tasking is pre-emptive. • Green Thread: These are user-space projections of the same concept as threads, but are not OS- managed. Probably not truly concurrent, except in the sense that there may be multiple worker threads or processes giving them CPU time concurrently, so probably best to consider this as interleaved or multiplexed. • Fibers: OS-managed. Exactly threads, except co-operatively multitasking, and hence not truly concurrent. • Coroutines: Exactly fibers, except not OS-managed. • Goroutines: They claim to be unlike anything else, but they seem to be exactly green threads, as in, process-managed in a single address space and multiplexed onto system threads. Perhaps somebody with more knowledge of Go can cut through the marketing material.
  • 22. 이런 개념들을 알아야 … async/await / yield fibers [stackless] continuations Suspendable Computations
  • 23. public CompletionStage<Boolean> addAdultItemAsync(final long productId, final long itemId) { log.trace("Add adult product cache. productId={}, itemId={}", productId, itemId); final RLock lock = getProductLock(productId); return lock.lockAsync(3000, TimeUnit.MILLISECONDS) .thenComposeAsync(rl -> updateProductItemMapping(productId, itemId), global) .thenComposeAsync(updated -> adultInverseIndex.fastPutAsync(itemId, productId), global) .thenComposeAsync(added -> adultProductItemMap.putAsync(productId, itemId), global) .whenCompleteAsync((result, error) -> lock.forceUnlock(), global); } Future combination is weired 😫
  • 24. Suspendable Computation asyncUI { val image = await(loadImage(url)) myUI.setImage(image) } Suspending call Time consuming operation UI Thread await(…) loadImage(url) Worker Thread setImage(…) Continuation
  • 25. Coroutines Goals • Asynchronous programming (and more) • without explicit callbacks • without explicit Future combinators (see Deathwing code) • Maximum flexibility for library designer • with minimal runtime support • and no macros (like Scala)
  • 26. Coroutines 종류 Stackless Stackful Language restrictions Use in special context 😫 Use anywhere 😀 Implemented in C#, Scala, Kotlin, … Quasar, Javaflow … Code transformation Local (compiler magic) 😀 All over the place 😫 Runtime support Little 😀 Substantial 😫
  • 27. The C# Way async Task<String> work() { Thread.sleep(200); return “done”; } async Task moreWork() { Console.WriteLine(“Work started”); var str = await work(); Console.WriteLine($“Work completed: {str}”); }
  • 28. The Kotlin Way fun work(): Deferred<String> = async(CommonPool) { delay(200). // non-blocking Thread.sleep() “done” } fun moreWork():Deferred<Unit> = async(CommonPool) { println(“Work started”) val str = await(work()) println(“Work completed: $str”) }
  • 29. How suspension works fun moreWork():Deferred<Unit> = async(CommonPool) { println(“Work started”) val str = await(work()) println(“Work completed: $str”) } controller.await( work(), current_continuation ) return
  • 30. Coroutines : Job @Test fun `coroutine is light-weight`() = runBlocking { val jobs = List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } }
  • 31. Yield example : Lazy Fibonacci val seq = buildSequence<Int> { var a = 0 var b = 1 yield(1) while (true) { yield(a + b) val tmp = a + b a = b b = tmp } } val list = seq.take(10).toList() assertThat(list).isEqualTo(listOf(1, 1, 2, 3, 5, 8, 13, 21, 34, 55))
  • 32. Channel @Test fun `channel basic`() = runBlocking { val channel = Channel<Int>() launch(CommonPool) { (1 .. 5).forEach { channel.send(it * it) } } repeat(5) { println(channel.receive()) } println("Done!") }
  • 34. Spring Framework 비동기 방식 • @Async • Async Request Processing • Callable • DeferedResult • ResponseBodyEmitter • AsyncRestTemplate
  • 35. @Async • SimpleAsyncTaskExecutor 를 이용하여, 지정한 작업을 수행 • Not ThreadPool !!! • @Async 는 실전에서는 사용하지 말 것 !!!
  • 36. Asychronous MVC 의 리턴 타입 • Callable<T> • WebAsyncTask<T> • DeferredResult<T> • ListenableFuture<T> • CompletionStage<T> • ResponseBodyEmitter
  • 37. @GetMapping("/composeasync2") DeferredResult<String> asyncCompose2() { DeferredResult dr = new DeferredResult(); ListenableFuture<String> f1 = myService.async(); f1.addCallback(res1 -> { ListenableFuture<String> f2 = myService.async2(res1); f2.addCallback(res2 -> { ListenableFuture<String> f3 = myService.async3(res2); f3.addCallback(res3 -> { dr.setResult(res3); }, e -> { dr.setErrorResult(e); }); }, e -> { dr.setErrorResult(e); }); }, e->{ dr.setErrorResult(e); }); return dr; } 알흠다운 콜백 헬
  • 38. AsyncRestTemplate • Spring 4.0 부터 RestTemplate 의 비동기-논블록킹 버전인 AsyncRestTemplate 제공 • 겉은 비동기-논블록킹이지만 논블록킹 IO 를 사용하지 않음 ㅠ. ㅠ • Netty 를 이용하여 논블록킹 IO (NioEventLoopEventGroup) 을 사용할 수 있음 • 리턴 타입이 ListenableFuture 라 콜백 헬 발생 !!!  ListenableFuture 를 Kotlin Coroutines 의 Deferred 로 변환 가능
  • 39. Async@Spring • TaskExecutor 의 전략적 활용이 중요 • 스프링의 모든 비동기 기술에는 ExecutorService 의 세밀한 설정이 가 능 • CompletableFuture 도 ExecutorService의 설계가 중요 • 비동기 스프링 기술을 사용하는 이유? • IO 가 많은 서버에서 서버 자원의 효율적 활용 Low Latency, High Throughput • 서버 외부 작업 • 그럼 Spring 에서 다른 방법은 없나 • Callback Hell 은 못 피하는 것인가? • Java 8 ForkJoin Pool 이나 Scala 의 Global Executor 을 쓰면 안되나? •
  • 41. Coroutines with Spring • Kotlin suspend 함수를 Spring 에서 직접 이용 • Spring TaskExecutor 를 사용하지 않고, ForkJoin Pool 사용 • Callback Hell 없이 async/await 사용 • Spring 에서 Kotlin Coroutines 의 다양한 기능 활용 • Async IO • Channel
  • 42. Coroutines 을 사용하기 위한 Spring Configuration @SpringBootApplication @EnableAutoConfiguration @EnableCoroutine @EnableWebCoroutine open class DemoAppConfiguration { @Bean fun demoService(): DemoService { return DemoService() } }
  • 43. open class DemoService { @Scheduled(fixedRate = 60_000) suspend open fun everyMinute() { log.info { "I'm still alive ... every minutes I will back..." } } suspend open fun delayedReturn(str: String, delayMillis: Long): String { delay(delayMillis) return str } @Coroutine(COMMON_POOL) suspend open fun commonPoolReturn(str: String, delayMillis: Long): String { delay(delayMillis) return str } }
  • 44. Coroutines 가 적용된 RestController @RestController open class DemoController @Inject constructor(private val demoService: DemoService) { private val restOperations = CoroutineRestOperations.invoke() @GetMapping("/delayed") suspend open fun delayedReturn(): String { log.info { "Before call to [demoService.delayed]" } val result = demoService.delayedReturn("delayed", 1000) log.info { "After call to [demoService.delayed]" } return result } @GetMapping("/commonPool") suspend open fun commonPoolReturn(): String { log.info { "Before call to [demoService.commonPoolReturn]" } val result = demoService.commonPoolReturn("commonPool", 1000) log.info { "After call to [demoService.commonPoolReturn]" } return result }
  • 45. @GetMapping("/rest") @Coroutine(COMMON_POOL) suspend open fun rest(request: HttpServletRequest): String { val result = restOperations.getForEntity(request.requestURL.toString() .replace("rest", "delayed"), String::class.java) return "Rest result: ${result.body}" } RestTemplate 에서 Coroutine 이 적용된 CoroutineRestOperations 인터페이스를 사용하여, 외부 서버 정보를 요청할 수도 있다.  RestTemplate 처럼 Blocking 되지 않는다. interface CoroutineRestOperations { companion object : KLogging() { operator fun invoke(restOperations: RestOperations = RestTemplate(), context: CoroutineContext = NewThreadCoroutineDispatcher): CoroutineRestOperations { log.info { "Create CoroutineRestOperations Proxy ..." } return createCoroutineProxy(CoroutineRestOperations::class.java, restOperations, DefaultCoroutineProxyConfig(context)) } } } suspend fun <T : Any?> getForEntity(url: String, responseType: Class<T>?, vararg uriVariables: Any?): ResponseEntity<T>
  • 46. Concolusion • 범용의 Spring Framework 에 Kotlin Coroutines 을 사용 • Low latency, High throughput 실현 • 비동기, 논 블럭킹을 Readable Code 로 구현 • Java CompletableFuture 의 thenXXXX 메소드에서 해방 • Spring context 를 이용하여 향후 retry, scheduled 등 다양한 방식의 구현체에 Coroutines 적용 예정 • Effective Java 를 배워서 구현하려면, 차라리 Kotlin 으로 구현 해라 • 향후 Kotlin Native 로 진정한 비동기 IO 를 사용할 수 있다.