Asynchronous programming with Kotlin coroutines in Spring Konrad - - PowerPoint PPT Presentation

asynchronous programming with kotlin coroutines in spring
SMART_READER_LITE
LIVE PREVIEW

Asynchronous programming with Kotlin coroutines in Spring Konrad - - PowerPoint PPT Presentation

Asynchronous programming with Kotlin coroutines in Spring Konrad Kami ski Allegro.pl @GetMapping("/users/{userId}/products) fun getProducts(@PathVariable userId: String): List<Product> { if


slide-1
SLIDE 1

Allegro.pl

Konrad Kamiński

Asynchronous programming with Kotlin coroutines in Spring

slide-2
SLIDE 2

@GetMapping("/users/{userId}/products”) fun getProducts(@PathVariable userId: String): List<Product> { if (userValidationService.isValidUser(userId)) { return productService.getProducts(userId) } else { throw UnauthorizedUserException(userId) } }

slide-3
SLIDE 3

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-4
SLIDE 4

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-5
SLIDE 5

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-6
SLIDE 6

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-7
SLIDE 7

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-8
SLIDE 8

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-9
SLIDE 9

suspend fun simpleFun(param: String): Int { delay(100) return 5678 } fun simpleFun(param: String, callback: Continuation<Int>): Any { val delayResult = delay(100, object : Continuation<Unit> {

  • verride val context: CoroutineContext get() = callback.context
  • verride fun resume(value: Unit) = callback.resume(5678)
  • verride fun resumeWithException(ex: Throwable) =

callback.resumeWithException(ex) }) return when (delayResult === COROUTINE_SUSPENDED) { true -> COROUTINE_SUSPENDED false -> 5678 } }

slide-10
SLIDE 10

@GetMapping("/users/{userId}/products") suspend fun getProducts(@PathVariable userId: String): List<Product> { if (userValidationService.isValidUser(userId)) { return productService.getProducts(userId) } else { throw UnauthorizedUserException(userId) } }

slide-11
SLIDE 11
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-12
SLIDE 12
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-13
SLIDE 13
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-14
SLIDE 14
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-15
SLIDE 15
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-16
SLIDE 16
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-17
SLIDE 17
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-18
SLIDE 18
  • bject: HandlerMethodArgumentResolver {
  • verride fun supportsParameter(param: MethodParameter) =

param.method.isSuspend && isContinuationClass(param.parameterType)

  • verride fun resolveArgument(param: MethodParameter,

container: ModelAndViewContainer,webRequest: NativeWebRequest, binderFactory: WebDataBinderFactory) =

  • bject: Continuation<Any> {

val deferredResult = DeferredResult<Any>()

  • verride val context: CoroutineContext get() =

EmptyCoroutineContext

  • verride fun resume(value: Any) { deferredResult.setResult(value) }
  • verride fun resumeWithException(exception: Throwable) {

deferredResult.setErrorResult(exception) } }.apply { container.model["deferred"] = deferredResult } }

slide-19
SLIDE 19
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-20
SLIDE 20
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-21
SLIDE 21
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-22
SLIDE 22
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-23
SLIDE 23
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-24
SLIDE 24
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-25
SLIDE 25
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-26
SLIDE 26
  • bject: AsyncHandlerMethodReturnValueHandler {

private val delegate = DeferredResultMethodReturnValueHandler()

  • verride fun supportsReturnType(returnType: MethodParameter): Boolean =

returnType.method.isSuspend

  • verride fun handleReturnValue(returnValue: Any?,

type: MethodParameter, container: ModelAndViewContainer, webRequest: NativeWebRequest) { val result = container.model["deferred"] as DeferredResult<*> return delegate.handleReturnValue(result, type, mavContainer, webRequest) }

  • verride fun isAsyncReturnValue(value: Any,type: MethodParameter) =

returnValue === COROUTINE_SUSPENDED }

slide-27
SLIDE 27

DEMO

https://github.com/konrad-kaminski/spring-kotlin-coroutine

slide-28
SLIDE 28
  • Asynchronous application
  • Imperative style
  • Non-blocking I/O
  • Scalability

Spring 5 + Kotlin coroutines

slide-29
SLIDE 29
  • @Cacheable
  • @EventListener & CoroutineEventPublisher
  • @Scheduled
  • Functional style route definitions

https://github.com/konrad-kaminski/spring-kotlin-coroutine

spring-kotlin-coroutine

slide-30
SLIDE 30

Allegro.pl

Konrad Kamiński

Thank you!