{"id":10084,"date":"2021-09-10T15:12:21","date_gmt":"2021-09-10T13:12:21","guid":{"rendered":"https:\/\/vived.io\/aop-w-polaczeniu-z-kotlin-coroutines\/"},"modified":"2022-09-19T13:11:00","modified_gmt":"2022-09-19T11:11:00","slug":"aop-w-polaczeniu-z-kotlin-coroutines","status":"publish","type":"post","link":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/","title":{"rendered":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines"},"content":{"rendered":"\n<p>Programowanie aspektowe (<em>aspect-oriented programming<\/em>) jest od d\u0142u\u017cszego czasu popularne w \u015bwiecie javowym. Biblioteki takie jak AspectJ czy Spring AOP pozwalaj\u0105 w \u0142atwy spos\u00f3b obs\u0142u\u017cy\u0107 <em>cross-cutting concerns<\/em>. Niestety, nie wspieraj\u0105 one oficjalnie Kotlin Coroutines, kt\u00f3re \u015bwietnie sprawdzaj\u0105 si\u0119 w pisaniu asynchronicznego, nieblokuj\u0105cego kodu. Czy jeste\u015bmy w stanie zmusi\u0107 aspekty do dzia\u0142ania z korutynami, pomimo braku oficjalnego wsparcia? Okazuje si\u0119, \u017ce tak.<\/p>\n\n\n\n<h2 id=\"problemy-w-laczeniu-aop-z-asynchronicznym-kodem\" data-num=1>Problemy w \u0142\u0105czeniu AOP z&nbsp;asynchronicznym kodem<\/h2>\n\n\n\n<p>Tradycyjnie w&nbsp;tych bibliotekach mamy dost\u0119pne rady (<em>advices<\/em>) umo\u017cliwiaj\u0105ce zdefiniowanie kodu, kt\u00f3ry ma zosta\u0107 wykonany na przyk\u0142ad przed wywo\u0142aniem metody (<code>before<\/code>), po zwr\u00f3ceniu warto\u015bci przez metod\u0119 (<code>after returning<\/code>) lub po rzuceniu wyj\u0105tku (<code>after throwing<\/code>). <\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class Foo {\n    @Logging\n    fun add(a: Int, b: Int): Int = a + b\n}\n\n@Aspect\nclass LoggingAspect {\n    @AfterReturning(\n        pointcut = &quot;@annotation(Logging)&quot;,\n        returning = &quot;result&quot;\n    )\n    fun logResult(joinPoint: JoinPoint, result: Any?) {\n        logger.debug(&quot;`${joinPoint.signature}` returned `${result}`&quot;)\n    }\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `int Foo.add(int,int)` returned `5`<\/code><\/pre>\n\n\n\n<p>O ile w tradycyjnym modelu r\u00f3wnoleg\u0142o\u015bci opartym o&nbsp;w\u0105tki i&nbsp;blokuj\u0105ce wywo\u0142ania sprawdza si\u0119 to dobrze, o&nbsp;tyle w&nbsp;nowszych podej\u015bciach opartych o asynchroniczno\u015b\u0107 jest ju\u017c gorzej. Je\u015bli u\u017cywamy Reactive Streams, cz\u0119sto b\u0119dziemy mieli metody, kt\u00f3re zamiast bezpo\u015brednio zwraca\u0107 warto\u015bci i rzuca\u0107 wyj\u0105tki, zwracaj\u0105 leniwe strumienie <code>Publisher&lt;T&gt;<\/code>, kt\u00f3re to emituj\u0105 warto\u015bci lub b\u0142\u0119dy (<code>onNext<\/code>\/<code>onError<\/code>). Pisanie aspekt\u00f3w staje si\u0119 troch\u0119 uci\u0105\u017cliwe, lecz wci\u0105\u017c wykonalne:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class ReactiveFoo {\n    @ReactiveLogging\n    fun add(a: Int, b: Int): Mono&lt;Int&gt; = Mono.just(a + b)\n}\n\n@Aspect\nclass ReactiveLoggingAspect {\n    @Around(&quot;&quot;&quot;\n        @annotation(ReactiveLogging) &amp;&amp;\n        execution(reactor.core.publisher.Mono *(..))\n    &quot;&quot;&quot;)\n    fun logResult(joinPoint: ProceedingJoinPoint): Mono&lt;Any&gt; =\n        (joinPoint.proceed() as Mono&lt;Any&gt;)\n            .doOnNext { result -&gt; \n                logger.debug(\n                    &quot;`${joinPoint.signature}` returned `${result}`&quot;\n                )\n            }\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Mono ReactiveFoo.add(int,int)` returned `5`<\/code><\/pre>\n\n\n\n<p>Gorzej jest w przypadku Kotlin Coroutines. AspectJ\/Spring AOP oficjalnie nie wspieraj\u0105 <em>suspending functions<\/em>. Na pierwszy rzut oka asynchroniczny kod oparty o korutyny niewiele r\u00f3\u017cni si\u0119 od klasycznego kodu synchronicznego. Widzimy s\u0142owo kluczowe <code>suspend<\/code> i&nbsp;niewiele poza tym. Kompilator Kotlina jednak do\u015b\u0107 mocno przekszta\u0142ca ten kod i na poziomie bytecodu otrzymujemy zmienione sygnatury metod, kt\u00f3re wykorzystuj\u0105 <em>Continuation Passing Style<\/em> i implementuj\u0105 maszyny stan\u00f3w.<\/p>\n\n\n\n<p>Spr\u00f3bujmy zaaplikowa\u0107 standardowy aspekt do <code>suspend fun<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class CoroutineFoo {\n    @Logging\n    suspend fun add(a: Int, b: Int): Int {\n        delay(100)\n        return a + b\n    }\n}<\/code><\/pre>\n\n\n\n<p>Po uruchomieniu sygnatura funkcji, jak i&nbsp;zwracana warto\u015b\u0107 mog\u0105 si\u0119 wydawa\u0107 inne od oczekiwanych:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `COROUTINE_SUSPENDED`<\/code><\/pre>\n\n\n\n<p>Ka\u017cda <code>suspend<\/code> funkcja na poziomie bytecodu JVM ma dodatkowy parametr <code>Continuation<\/code>. Jej zwracany typ to <code>Object<\/code>, poniewa\u017c opr\u00f3cz typu zadeklarowanego w Kotlinie, mo\u017ce te\u017c zwr\u00f3ci\u0107 magiczn\u0105 warto\u015b\u0107 <code>COROUTINE_SUSPENDED<\/code>.<\/p>\n\n\n\n<h2 id=\"jak-zmusic-aspekty-do-dzialania-z-korutynami\" data-num=2>Jak zmusi\u0107 aspekty do dzia\u0142ania z&nbsp;korutynami?<\/h2>\n\n\n\n<p>Zauwa\u017cmy, \u017ce sygnatury funkcji <code>suspend fun f(): T<\/code> oraz <code>fun f(c: Continuation): Any?<\/code> z punktu widzenia JVM s\u0105 identyczne. Z&nbsp;punktu widzenia Kotlina, w pierwszej <code>Continuation<\/code> jest przekazywane <em>implicite<\/em>, w&nbsp;drugiej <em>explicite<\/em>. Pierwsza nie jest wspierana przez AspectJ, ale druga ju\u017c jest.<\/p>\n\n\n\n<p>Do zdefiniowania aspektu wykorzystamy punkt ci\u0119cia (<em>pointcut<\/em>) <code>args(.., kotlin.coroutines.Continuation)<\/code> oraz rad\u0119 (<em>advice<\/em>) <em>around<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Around(&quot;&quot;&quot;\n    @annotation(CoroutineLogging) &amp;&amp;\n    args(.., kotlin.coroutines.Continuation)\n&quot;&quot;&quot;)\nfun logResult(joinPoint: ProceedingJoinPoint): Any? { }<\/code><\/pre>\n\n\n\n<p>Z <code>ProceedingJoinPoint<\/code> potrzebujemy wyci\u0105gn\u0105\u0107 argumenty, z kt\u00f3rymi zosta\u0142a wywo\u0142ana funkcja, w szczeg\u00f3lno\u015bci ostatni argument typu <code>Continuation<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">val ProceedingJoinPoint.coroutineContinuation: Continuation&lt;Any?&gt;  \n    get() = this.args.last() as Continuation&lt;Any?&gt;  \n\nval ProceedingJoinPoint.coroutineArgs: Array&lt;Any?&gt;  \n    get() = this.args.sliceArray(0 until this.args.size - 1)<\/code><\/pre>\n\n\n\n<p>Pozwala nam to na zaimplementowanie odpowiednika <code>ProceedingJoinPoint.proceed()<\/code> zdefiniowanego jako <code>suspend fun<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn\n\nsuspend fun ProceedingJoinPoint.proceedCoroutine(\n    args: Array&lt;Any?&gt; = this.coroutineArgs\n): Any? =\n    suspendCoroutineUninterceptedOrReturn { continuation -&gt;  \n        this.proceed(args + continuation)  \n    }<\/code><\/pre>\n\n\n\n<p>Wykorzystuj\u0105c <code>ProceedingJoinPoint.coroutineContinuation<\/code>, kt\u00f3re zdefiniowali\u015bmy chwil\u0119 wcze\u015bniej, mo\u017cemy wywo\u0142a\u0107 dowoln\u0105 funkcj\u0119 <code>suspend<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn\n\nfun ProceedingJoinPoint.runCoroutine(\n    block: suspend () -&gt; Any?\n): Any? =\n    block.startCoroutineUninterceptedOrReturn(this.coroutineContinuation)<\/code><\/pre>\n\n\n\n<p>Sk\u0142adaj\u0105c to wszystko razem, otrzymujemy aspekt dzia\u0142aj\u0105cy z&nbsp;korutynami:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Aspect\nclass CoroutineLoggingAspect {  \n    @Around(&quot;&quot;&quot;\n        @annotation(CoroutineLogging) &amp;&amp;\n        args(.., kotlin.coroutines.Continuation)\n    &quot;&quot;&quot;)\n    fun logResult(joinPoint: ProceedingJoinPoint): Any? =  \n        joinPoint.runCoroutine {\n            val result = joinPoint.proceedCoroutine()  \n            logger.debug(&quot;`${joinPoint.signature}` returned `${result}`&quot;)  \n            result\n        }\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `5`<\/code><\/pre>\n\n\n\n<p>Pe\u0142ny kod \u017ar\u00f3d\u0142owy znajdziecie <a href=\"https:\/\/gist.github.com\/pjanczyk\/5d958821bafd911a5996bc0b66788ea3\">tutaj<\/a>.<\/p>\n\n\n\n<h2 id=\"podsumowanie\" data-num=3>Podsumowanie<\/h2>\n\n\n\n<p>U\u017cywanie aspekt\u00f3w z korutynami jest jak najbardziej mo\u017cliwe. Pomimo braku oficjalnego wsparcia przy odrobinie dodatkowego kodu jeste\u015bmy w stanie po\u0142\u0105czy\u0107 programowanie aspektowe z modelem asynchronicznym. Aspekty mog\u0105 nam si\u0119 przyda\u0107 przy implementowaniu <meta charset=\"utf-8\"><em>cross-cutting concerns<\/em> takich jak <em>logging<\/em>, <em>tracing<\/em> i tym podobne.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.<\/p>\n","protected":false},"author":11,"featured_media":7687,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[259],"tags":[],"class_list":["post-10084","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-jvm-pl"],"acf":{"estimated_reading_time":"3","weekly_summary":true},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived<\/title>\n<meta name=\"description\" content=\"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\" \/>\n<meta property=\"og:locale\" content=\"pl_PL\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived\" \/>\n<meta property=\"og:description\" content=\"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\" \/>\n<meta property=\"og:site_name\" content=\"Vived\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-10T13:12:21+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-09-19T11:11:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1811\" \/>\n\t<meta property=\"og:image:height\" content=\"947\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Piotr Janczyk\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\"},\"author\":{\"name\":\"Piotr Janczyk\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/e70dbea3d2cce915c4bab73c3eb6bf76\"},\"headline\":\"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines\",\"datePublished\":\"2021-09-10T13:12:21+00:00\",\"dateModified\":\"2022-09-19T11:11:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\"},\"wordCount\":494,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/vived.io\/pl\/#organization\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png\",\"articleSection\":[\"JVM\"],\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\",\"url\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\",\"name\":\"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived\",\"isPartOf\":{\"@id\":\"https:\/\/vived.io\/pl\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png\",\"datePublished\":\"2021-09-10T13:12:21+00:00\",\"dateModified\":\"2022-09-19T11:11:00+00:00\",\"description\":\"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.\",\"breadcrumb\":{\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#breadcrumb\"},\"inLanguage\":\"pl-PL\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage\",\"url\":\"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png\",\"contentUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png\",\"width\":1811,\"height\":947},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Strona g\u0142\u00f3wna\",\"item\":\"https:\/\/vived.io\/pl\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/vived.io\/pl\/#website\",\"url\":\"https:\/\/vived.io\/pl\/\",\"name\":\"Vived\",\"description\":\"platform empowering IT people and technology companies to synergic growth\",\"publisher\":{\"@id\":\"https:\/\/vived.io\/pl\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/vived.io\/pl\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pl-PL\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/vived.io\/pl\/#organization\",\"name\":\"Vived\",\"url\":\"https:\/\/vived.io\/pl\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png\",\"contentUrl\":\"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png\",\"width\":136,\"height\":45,\"caption\":\"Vived\"},\"image\":{\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/e70dbea3d2cce915c4bab73c3eb6bf76\",\"name\":\"Piotr Janczyk\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pl-PL\",\"@id\":\"https:\/\/vived.io\/pl\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0aa18c2e3651298acdb6f64c09dd7cd3cbd2ad8f6ef3a17610e4f485be5c55ec?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0aa18c2e3651298acdb6f64c09dd7cd3cbd2ad8f6ef3a17610e4f485be5c55ec?s=96&d=mm&r=g\",\"caption\":\"Piotr Janczyk\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived","description":"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/","og_locale":"pl_PL","og_type":"article","og_title":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived","og_description":"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.","og_url":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/","og_site_name":"Vived","article_published_time":"2021-09-10T13:12:21+00:00","article_modified_time":"2022-09-19T11:11:00+00:00","og_image":[{"width":1811,"height":947,"url":"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png","type":"image\/png"}],"author":"Piotr Janczyk","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#article","isPartOf":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/"},"author":{"name":"Piotr Janczyk","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/e70dbea3d2cce915c4bab73c3eb6bf76"},"headline":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines","datePublished":"2021-09-10T13:12:21+00:00","dateModified":"2022-09-19T11:11:00+00:00","mainEntityOfPage":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/"},"wordCount":494,"commentCount":0,"publisher":{"@id":"https:\/\/vived.io\/pl\/#organization"},"image":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage"},"thumbnailUrl":"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png","articleSection":["JVM"],"inLanguage":"pl-PL","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/","url":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/","name":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines - Vived","isPartOf":{"@id":"https:\/\/vived.io\/pl\/#website"},"primaryImageOfPage":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage"},"image":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage"},"thumbnailUrl":"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png","datePublished":"2021-09-10T13:12:21+00:00","dateModified":"2022-09-19T11:11:00+00:00","description":"Jak zmusi\u0107 AspectJ\/Spring AOP do dzia\u0142ania z korutynami? Zobaczmy jak po\u0142\u0105czy\u0107 programowanie aspektowe z asynchroniczno\u015bci\u0105.","breadcrumb":{"@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#breadcrumb"},"inLanguage":"pl-PL","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/"]}]},{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#primaryimage","url":"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png","contentUrl":"https:\/\/vived.io\/wp-content\/uploads\/2021\/09\/aop-w-polaczeniu-z-kotlin-coroutines.png","width":1811,"height":947},{"@type":"BreadcrumbList","@id":"https:\/\/vived.io\/pl\/aop-w-polaczeniu-z-kotlin-coroutines\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Strona g\u0142\u00f3wna","item":"https:\/\/vived.io\/pl\/"},{"@type":"ListItem","position":2,"name":"AOP w po\u0142\u0105czeniu z\u00a0Kotlin Coroutines"}]},{"@type":"WebSite","@id":"https:\/\/vived.io\/pl\/#website","url":"https:\/\/vived.io\/pl\/","name":"Vived","description":"platform empowering IT people and technology companies to synergic growth","publisher":{"@id":"https:\/\/vived.io\/pl\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vived.io\/pl\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pl-PL"},{"@type":"Organization","@id":"https:\/\/vived.io\/pl\/#organization","name":"Vived","url":"https:\/\/vived.io\/pl\/","logo":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/","url":"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png","contentUrl":"https:\/\/vived.io\/wp-content\/uploads\/2020\/03\/logo_vived_color.png","width":136,"height":45,"caption":"Vived"},"image":{"@id":"https:\/\/vived.io\/pl\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/e70dbea3d2cce915c4bab73c3eb6bf76","name":"Piotr Janczyk","image":{"@type":"ImageObject","inLanguage":"pl-PL","@id":"https:\/\/vived.io\/pl\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0aa18c2e3651298acdb6f64c09dd7cd3cbd2ad8f6ef3a17610e4f485be5c55ec?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0aa18c2e3651298acdb6f64c09dd7cd3cbd2ad8f6ef3a17610e4f485be5c55ec?s=96&d=mm&r=g","caption":"Piotr Janczyk"}}]}},"blocks_vived":[{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Programowanie aspektowe (<em>aspect-oriented programming<\/em>) jest od d\u0142u\u017cszego czasu popularne w \u015bwiecie javowym. Biblioteki takie jak AspectJ czy Spring AOP pozwalaj\u0105 w \u0142atwy spos\u00f3b obs\u0142u\u017cy\u0107 <em>cross-cutting concerns<\/em>. Niestety, nie wspieraj\u0105 one oficjalnie Kotlin Coroutines, kt\u00f3re \u015bwietnie sprawdzaj\u0105 si\u0119 w pisaniu asynchronicznego, nieblokuj\u0105cego kodu. Czy jeste\u015bmy w stanie zmusi\u0107 aspekty do dzia\u0142ania z korutynami, pomimo braku oficjalnego wsparcia? Okazuje si\u0119, \u017ce tak.<\/p>\n","innerContent":["\n<p>Programowanie aspektowe (<em>aspect-oriented programming<\/em>) jest od d\u0142u\u017cszego czasu popularne w \u015bwiecie javowym. Biblioteki takie jak AspectJ czy Spring AOP pozwalaj\u0105 w \u0142atwy spos\u00f3b obs\u0142u\u017cy\u0107 <em>cross-cutting concerns<\/em>. Niestety, nie wspieraj\u0105 one oficjalnie Kotlin Coroutines, kt\u00f3re \u015bwietnie sprawdzaj\u0105 si\u0119 w pisaniu asynchronicznego, nieblokuj\u0105cego kodu. Czy jeste\u015bmy w stanie zmusi\u0107 aspekty do dzia\u0142ania z korutynami, pomimo braku oficjalnego wsparcia? Okazuje si\u0119, \u017ce tak.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>Problemy w \u0142\u0105czeniu AOP z&nbsp;asynchronicznym kodem<\/h2>\n","innerContent":["\n<h2>Problemy w \u0142\u0105czeniu AOP z&nbsp;asynchronicznym kodem<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Tradycyjnie w&nbsp;tych bibliotekach mamy dost\u0119pne rady (<em>advices<\/em>) umo\u017cliwiaj\u0105ce zdefiniowanie kodu, kt\u00f3ry ma zosta\u0107 wykonany na przyk\u0142ad przed wywo\u0142aniem metody (<code>before<\/code>), po zwr\u00f3ceniu warto\u015bci przez metod\u0119 (<code>after returning<\/code>) lub po rzuceniu wyj\u0105tku (<code>after throwing<\/code>). <\/p>\n","innerContent":["\n<p>Tradycyjnie w&nbsp;tych bibliotekach mamy dost\u0119pne rady (<em>advices<\/em>) umo\u017cliwiaj\u0105ce zdefiniowanie kodu, kt\u00f3ry ma zosta\u0107 wykonany na przyk\u0142ad przed wywo\u0142aniem metody (<code>before<\/code>), po zwr\u00f3ceniu warto\u015bci przez metod\u0119 (<code>after returning<\/code>) lub po rzuceniu wyj\u0105tku (<code>after throwing<\/code>). <\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class Foo {\n    @Logging\n    fun add(a: Int, b: Int): Int = a + b\n}\n\n@Aspect\nclass LoggingAspect {\n    @AfterReturning(\n        pointcut = \"@annotation(Logging)\",\n        returning = \"result\"\n    )\n    fun logResult(joinPoint: JoinPoint, result: Any?) {\n        logger.debug(\"`${joinPoint.signature}` returned `${result}`\")\n    }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class Foo {\n    @Logging\n    fun add(a: Int, b: Int): Int = a + b\n}\n\n@Aspect\nclass LoggingAspect {\n    @AfterReturning(\n        pointcut = \"@annotation(Logging)\",\n        returning = \"result\"\n    )\n    fun logResult(joinPoint: JoinPoint, result: Any?) {\n        logger.debug(\"`${joinPoint.signature}` returned `${result}`\")\n    }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"plaintext"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `int Foo.add(int,int)` returned `5`<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `int Foo.add(int,int)` returned `5`<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>O ile w tradycyjnym modelu r\u00f3wnoleg\u0142o\u015bci opartym o&nbsp;w\u0105tki i&nbsp;blokuj\u0105ce wywo\u0142ania sprawdza si\u0119 to dobrze, o&nbsp;tyle w&nbsp;nowszych podej\u015bciach opartych o asynchroniczno\u015b\u0107 jest ju\u017c gorzej. Je\u015bli u\u017cywamy Reactive Streams, cz\u0119sto b\u0119dziemy mieli metody, kt\u00f3re zamiast bezpo\u015brednio zwraca\u0107 warto\u015bci i rzuca\u0107 wyj\u0105tki, zwracaj\u0105 leniwe strumienie <code>Publisher&lt;T&gt;<\/code>, kt\u00f3re to emituj\u0105 warto\u015bci lub b\u0142\u0119dy (<code>onNext<\/code>\/<code>onError<\/code>). Pisanie aspekt\u00f3w staje si\u0119 troch\u0119 uci\u0105\u017cliwe, lecz wci\u0105\u017c wykonalne:<\/p>\n","innerContent":["\n<p>O ile w tradycyjnym modelu r\u00f3wnoleg\u0142o\u015bci opartym o&nbsp;w\u0105tki i&nbsp;blokuj\u0105ce wywo\u0142ania sprawdza si\u0119 to dobrze, o&nbsp;tyle w&nbsp;nowszych podej\u015bciach opartych o asynchroniczno\u015b\u0107 jest ju\u017c gorzej. Je\u015bli u\u017cywamy Reactive Streams, cz\u0119sto b\u0119dziemy mieli metody, kt\u00f3re zamiast bezpo\u015brednio zwraca\u0107 warto\u015bci i rzuca\u0107 wyj\u0105tki, zwracaj\u0105 leniwe strumienie <code>Publisher&lt;T&gt;<\/code>, kt\u00f3re to emituj\u0105 warto\u015bci lub b\u0142\u0119dy (<code>onNext<\/code>\/<code>onError<\/code>). Pisanie aspekt\u00f3w staje si\u0119 troch\u0119 uci\u0105\u017cliwe, lecz wci\u0105\u017c wykonalne:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class ReactiveFoo {\n    @ReactiveLogging\n    fun add(a: Int, b: Int): Mono&lt;Int> = Mono.just(a + b)\n}\n\n@Aspect\nclass ReactiveLoggingAspect {\n    @Around(\"\"\"\n        @annotation(ReactiveLogging) &amp;&amp;\n        execution(reactor.core.publisher.Mono *(..))\n    \"\"\")\n    fun logResult(joinPoint: ProceedingJoinPoint): Mono&lt;Any> =\n        (joinPoint.proceed() as Mono&lt;Any>)\n            .doOnNext { result -> \n                logger.debug(\n                    \"`${joinPoint.signature}` returned `${result}`\"\n                )\n            }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class ReactiveFoo {\n    @ReactiveLogging\n    fun add(a: Int, b: Int): Mono&lt;Int> = Mono.just(a + b)\n}\n\n@Aspect\nclass ReactiveLoggingAspect {\n    @Around(\"\"\"\n        @annotation(ReactiveLogging) &amp;&amp;\n        execution(reactor.core.publisher.Mono *(..))\n    \"\"\")\n    fun logResult(joinPoint: ProceedingJoinPoint): Mono&lt;Any> =\n        (joinPoint.proceed() as Mono&lt;Any>)\n            .doOnNext { result -> \n                logger.debug(\n                    \"`${joinPoint.signature}` returned `${result}`\"\n                )\n            }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"plaintext"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Mono ReactiveFoo.add(int,int)` returned `5`<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Mono ReactiveFoo.add(int,int)` returned `5`<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Gorzej jest w przypadku Kotlin Coroutines. AspectJ\/Spring AOP oficjalnie nie wspieraj\u0105 <em>suspending functions<\/em>. Na pierwszy rzut oka asynchroniczny kod oparty o korutyny niewiele r\u00f3\u017cni si\u0119 od klasycznego kodu synchronicznego. Widzimy s\u0142owo kluczowe <code>suspend<\/code> i&nbsp;niewiele poza tym. Kompilator Kotlina jednak do\u015b\u0107 mocno przekszta\u0142ca ten kod i na poziomie bytecodu otrzymujemy zmienione sygnatury metod, kt\u00f3re wykorzystuj\u0105 <em>Continuation Passing Style<\/em> i implementuj\u0105 maszyny stan\u00f3w.<\/p>\n","innerContent":["\n<p>Gorzej jest w przypadku Kotlin Coroutines. AspectJ\/Spring AOP oficjalnie nie wspieraj\u0105 <em>suspending functions<\/em>. Na pierwszy rzut oka asynchroniczny kod oparty o korutyny niewiele r\u00f3\u017cni si\u0119 od klasycznego kodu synchronicznego. Widzimy s\u0142owo kluczowe <code>suspend<\/code> i&nbsp;niewiele poza tym. Kompilator Kotlina jednak do\u015b\u0107 mocno przekszta\u0142ca ten kod i na poziomie bytecodu otrzymujemy zmienione sygnatury metod, kt\u00f3re wykorzystuj\u0105 <em>Continuation Passing Style<\/em> i implementuj\u0105 maszyny stan\u00f3w.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Spr\u00f3bujmy zaaplikowa\u0107 standardowy aspekt do <code>suspend fun<\/code>:<\/p>\n","innerContent":["\n<p>Spr\u00f3bujmy zaaplikowa\u0107 standardowy aspekt do <code>suspend fun<\/code>:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class CoroutineFoo {\n    @Logging\n    suspend fun add(a: Int, b: Int): Int {\n        delay(100)\n        return a + b\n    }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">class CoroutineFoo {\n    @Logging\n    suspend fun add(a: Int, b: Int): Int {\n        delay(100)\n        return a + b\n    }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Po uruchomieniu sygnatura funkcji, jak i&nbsp;zwracana warto\u015b\u0107 mog\u0105 si\u0119 wydawa\u0107 inne od oczekiwanych:<\/p>\n","innerContent":["\n<p>Po uruchomieniu sygnatura funkcji, jak i&nbsp;zwracana warto\u015b\u0107 mog\u0105 si\u0119 wydawa\u0107 inne od oczekiwanych:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"plaintext"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `COROUTINE_SUSPENDED`<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `COROUTINE_SUSPENDED`<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Ka\u017cda <code>suspend<\/code> funkcja na poziomie bytecodu JVM ma dodatkowy parametr <code>Continuation<\/code>. Jej zwracany typ to <code>Object<\/code>, poniewa\u017c opr\u00f3cz typu zadeklarowanego w Kotlinie, mo\u017ce te\u017c zwr\u00f3ci\u0107 magiczn\u0105 warto\u015b\u0107 <code>COROUTINE_SUSPENDED<\/code>.<\/p>\n","innerContent":["\n<p>Ka\u017cda <code>suspend<\/code> funkcja na poziomie bytecodu JVM ma dodatkowy parametr <code>Continuation<\/code>. Jej zwracany typ to <code>Object<\/code>, poniewa\u017c opr\u00f3cz typu zadeklarowanego w Kotlinie, mo\u017ce te\u017c zwr\u00f3ci\u0107 magiczn\u0105 warto\u015b\u0107 <code>COROUTINE_SUSPENDED<\/code>.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>Jak zmusi\u0107 aspekty do dzia\u0142ania z&nbsp;korutynami?<\/h2>\n","innerContent":["\n<h2>Jak zmusi\u0107 aspekty do dzia\u0142ania z&nbsp;korutynami?<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Zauwa\u017cmy, \u017ce sygnatury funkcji <code>suspend fun f(): T<\/code> oraz <code>fun f(c: Continuation): Any?<\/code> z punktu widzenia JVM s\u0105 identyczne. Z&nbsp;punktu widzenia Kotlina, w pierwszej <code>Continuation<\/code> jest przekazywane <em>implicite<\/em>, w&nbsp;drugiej <em>explicite<\/em>. Pierwsza nie jest wspierana przez AspectJ, ale druga ju\u017c jest.<\/p>\n","innerContent":["\n<p>Zauwa\u017cmy, \u017ce sygnatury funkcji <code>suspend fun f(): T<\/code> oraz <code>fun f(c: Continuation): Any?<\/code> z punktu widzenia JVM s\u0105 identyczne. Z&nbsp;punktu widzenia Kotlina, w pierwszej <code>Continuation<\/code> jest przekazywane <em>implicite<\/em>, w&nbsp;drugiej <em>explicite<\/em>. Pierwsza nie jest wspierana przez AspectJ, ale druga ju\u017c jest.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Do zdefiniowania aspektu wykorzystamy punkt ci\u0119cia (<em>pointcut<\/em>) <code>args(.., kotlin.coroutines.Continuation)<\/code> oraz rad\u0119 (<em>advice<\/em>) <em>around<\/em>:<\/p>\n","innerContent":["\n<p>Do zdefiniowania aspektu wykorzystamy punkt ci\u0119cia (<em>pointcut<\/em>) <code>args(.., kotlin.coroutines.Continuation)<\/code> oraz rad\u0119 (<em>advice<\/em>) <em>around<\/em>:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Around(\"\"\"\n    @annotation(CoroutineLogging) &amp;&amp;\n    args(.., kotlin.coroutines.Continuation)\n\"\"\")\nfun logResult(joinPoint: ProceedingJoinPoint): Any? { }<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Around(\"\"\"\n    @annotation(CoroutineLogging) &amp;&amp;\n    args(.., kotlin.coroutines.Continuation)\n\"\"\")\nfun logResult(joinPoint: ProceedingJoinPoint): Any? { }<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Z <code>ProceedingJoinPoint<\/code> potrzebujemy wyci\u0105gn\u0105\u0107 argumenty, z kt\u00f3rymi zosta\u0142a wywo\u0142ana funkcja, w szczeg\u00f3lno\u015bci ostatni argument typu <code>Continuation<\/code>:<\/p>\n","innerContent":["\n<p>Z <code>ProceedingJoinPoint<\/code> potrzebujemy wyci\u0105gn\u0105\u0107 argumenty, z kt\u00f3rymi zosta\u0142a wywo\u0142ana funkcja, w szczeg\u00f3lno\u015bci ostatni argument typu <code>Continuation<\/code>:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">val ProceedingJoinPoint.coroutineContinuation: Continuation&lt;Any?>  \n    get() = this.args.last() as Continuation&lt;Any?>  \n\nval ProceedingJoinPoint.coroutineArgs: Array&lt;Any?>  \n    get() = this.args.sliceArray(0 until this.args.size - 1)<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">val ProceedingJoinPoint.coroutineContinuation: Continuation&lt;Any?>  \n    get() = this.args.last() as Continuation&lt;Any?>  \n\nval ProceedingJoinPoint.coroutineArgs: Array&lt;Any?>  \n    get() = this.args.sliceArray(0 until this.args.size - 1)<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Pozwala nam to na zaimplementowanie odpowiednika <code>ProceedingJoinPoint.proceed()<\/code> zdefiniowanego jako <code>suspend fun<\/code>:<\/p>\n","innerContent":["\n<p>Pozwala nam to na zaimplementowanie odpowiednika <code>ProceedingJoinPoint.proceed()<\/code> zdefiniowanego jako <code>suspend fun<\/code>:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn\n\nsuspend fun ProceedingJoinPoint.proceedCoroutine(\n    args: Array&lt;Any?> = this.coroutineArgs\n): Any? =\n    suspendCoroutineUninterceptedOrReturn { continuation ->  \n        this.proceed(args + continuation)  \n    }<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn\n\nsuspend fun ProceedingJoinPoint.proceedCoroutine(\n    args: Array&lt;Any?> = this.coroutineArgs\n): Any? =\n    suspendCoroutineUninterceptedOrReturn { continuation ->  \n        this.proceed(args + continuation)  \n    }<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Wykorzystuj\u0105c <code>ProceedingJoinPoint.coroutineContinuation<\/code>, kt\u00f3re zdefiniowali\u015bmy chwil\u0119 wcze\u015bniej, mo\u017cemy wywo\u0142a\u0107 dowoln\u0105 funkcj\u0119 <code>suspend<\/code>:<\/p>\n","innerContent":["\n<p>Wykorzystuj\u0105c <code>ProceedingJoinPoint.coroutineContinuation<\/code>, kt\u00f3re zdefiniowali\u015bmy chwil\u0119 wcze\u015bniej, mo\u017cemy wywo\u0142a\u0107 dowoln\u0105 funkcj\u0119 <code>suspend<\/code>:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn\n\nfun ProceedingJoinPoint.runCoroutine(\n    block: suspend () -> Any?\n): Any? =\n    block.startCoroutineUninterceptedOrReturn(this.coroutineContinuation)<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">import kotlin.coroutines.intrinsics.startCoroutineUninterceptedOrReturn\n\nfun ProceedingJoinPoint.runCoroutine(\n    block: suspend () -> Any?\n): Any? =\n    block.startCoroutineUninterceptedOrReturn(this.coroutineContinuation)<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Sk\u0142adaj\u0105c to wszystko razem, otrzymujemy aspekt dzia\u0142aj\u0105cy z&nbsp;korutynami:<\/p>\n","innerContent":["\n<p>Sk\u0142adaj\u0105c to wszystko razem, otrzymujemy aspekt dzia\u0142aj\u0105cy z&nbsp;korutynami:<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"kotlin"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Aspect\nclass CoroutineLoggingAspect {  \n    @Around(\"\"\"\n        @annotation(CoroutineLogging) &amp;&amp;\n        args(.., kotlin.coroutines.Continuation)\n    \"\"\")\n    fun logResult(joinPoint: ProceedingJoinPoint): Any? =  \n        joinPoint.runCoroutine {\n            val result = joinPoint.proceedCoroutine()  \n            logger.debug(\"`${joinPoint.signature}` returned `${result}`\")  \n            result\n        }\n}<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-kotlin\">@Aspect\nclass CoroutineLoggingAspect {  \n    @Around(\"\"\"\n        @annotation(CoroutineLogging) &amp;&amp;\n        args(.., kotlin.coroutines.Continuation)\n    \"\"\")\n    fun logResult(joinPoint: ProceedingJoinPoint): Any? =  \n        joinPoint.runCoroutine {\n            val result = joinPoint.proceedCoroutine()  \n            logger.debug(\"`${joinPoint.signature}` returned `${result}`\")  \n            result\n        }\n}<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"prismatic\/blocks","attrs":{"language":"plaintext"},"innerBlocks":[],"innerHTML":"\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `5`<\/code><\/pre>\n","innerContent":["\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-plaintext\">[DEBUG] `Object CoroutineFoo.add(int,int,Continuation)` returned `5`<\/code><\/pre>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>Pe\u0142ny kod \u017ar\u00f3d\u0142owy znajdziecie <a href=\"https:\/\/gist.github.com\/pjanczyk\/5d958821bafd911a5996bc0b66788ea3\">tutaj<\/a>.<\/p>\n","innerContent":["\n<p>Pe\u0142ny kod \u017ar\u00f3d\u0142owy znajdziecie <a href=\"https:\/\/gist.github.com\/pjanczyk\/5d958821bafd911a5996bc0b66788ea3\">tutaj<\/a>.<\/p>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/heading","attrs":[],"innerBlocks":[],"innerHTML":"\n<h2>Podsumowanie<\/h2>\n","innerContent":["\n<h2>Podsumowanie<\/h2>\n"]},{"blockName":null,"attrs":[],"innerBlocks":[],"innerHTML":"\n\n","innerContent":["\n\n"]},{"blockName":"core\/paragraph","attrs":[],"innerBlocks":[],"innerHTML":"\n<p>U\u017cywanie aspekt\u00f3w z korutynami jest jak najbardziej mo\u017cliwe. Pomimo braku oficjalnego wsparcia przy odrobinie dodatkowego kodu jeste\u015bmy w stanie po\u0142\u0105czy\u0107 programowanie aspektowe z modelem asynchronicznym. Aspekty mog\u0105 nam si\u0119 przyda\u0107 przy implementowaniu <meta charset=\"utf-8\"><em>cross-cutting concerns<\/em> takich jak <em>logging<\/em>, <em>tracing<\/em> i tym podobne.<\/p>\n","innerContent":["\n<p>U\u017cywanie aspekt\u00f3w z korutynami jest jak najbardziej mo\u017cliwe. Pomimo braku oficjalnego wsparcia przy odrobinie dodatkowego kodu jeste\u015bmy w stanie po\u0142\u0105czy\u0107 programowanie aspektowe z modelem asynchronicznym. Aspekty mog\u0105 nam si\u0119 przyda\u0107 przy implementowaniu <meta charset=\"utf-8\"><em>cross-cutting concerns<\/em> takich jak <em>logging<\/em>, <em>tracing<\/em> i tym podobne.<\/p>\n"]}],"_links":{"self":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/10084","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/comments?post=10084"}],"version-history":[{"count":1,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/10084\/revisions"}],"predecessor-version":[{"id":10594,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/posts\/10084\/revisions\/10594"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/media\/7687"}],"wp:attachment":[{"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/media?parent=10084"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/categories?post=10084"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vived.io\/pl\/wp-json\/wp\/v2\/tags?post=10084"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}