Micronaut Kotlin 支持

2023-03-13 15:04 更新

Micronaut 的命令行界面包括對 Kotlin 的特殊支持。要創(chuàng)建 Kotlin 應(yīng)用程序,請使用 kotlin lang 選項(xiàng)。例如:

創(chuàng)建 Micronaut Kotlin 應(yīng)用程序

$ mn create-app hello-world --lang kotlin

Micronaut 中對 Kotlin 的支持建立在 Kapt 編譯器插件之上,其中包括對 Java 注釋處理器的支持。要在您的 Micronaut 應(yīng)用程序中使用 Kotlin,請?zhí)砑舆m當(dāng)?shù)囊蕾図?xiàng)以在您的 kt 源文件上配置和運(yùn)行 kapt。 Kapt 為您的 Kotlin 類創(chuàng)建 Java“存根”類,然后可以由 Micronaut 的 Java 注釋處理器進(jìn)行處理。存根不包含在最終編譯的應(yīng)用程序中。

官方文檔中了解有關(guān) kapt 及其功能的更多信息。

使用 Gradle 時,Micronaut 注釋處理器在 kapt 范圍內(nèi)聲明。例如:

Example build.gradle

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" (1)
    compile "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
    kapt "io.micronaut:micronaut-inject-java" (2)

    kaptTest "io.micronaut:micronaut-inject-java" (3)
    ...
}
  1. 添加 Kotlin 標(biāo)準(zhǔn)庫

  2. 在kapt作用域下添加micronaut-inject-java依賴,這樣src/main中的類就會被處理

  3. 在 kaptTest 范圍下添加 micronaut-inject-java 依賴項(xiàng),以便處理 src/test 中的類。

使用與上面類似的 build.gradle 文件,您現(xiàn)在可以使用運(yùn)行任務(wù)(由 Application 插件提供)來運(yùn)行您的 Micronaut 應(yīng)用程序:

$ ./gradlew run

下面是一個用 Kotlin 編寫的示例控制器:

src/main/kotlin/example/HelloController.kt

package example

import io.micronaut.http.annotation.*

@Controller("/")
class HelloController {

    @Get("/hello/{name}")
    fun hello(name: String): String {
        return "Hello $name"
    }
}

Kotlin, Kapt and IntelliJ

在撰寫本文時,IntelliJ 的內(nèi)置編譯器不直接支持 Kapt 和注釋處理。在運(yùn)行測試或應(yīng)用程序類之前,您必須將 Intellij 配置為運(yùn)行 Gradle(或 Maven)編譯作為構(gòu)建步驟。

首先,編輯測試或應(yīng)用程序的運(yùn)行配置,然后選擇“運(yùn)行 Gradle 任務(wù)”作為構(gòu)建步驟:


然后將類任務(wù)添加為應(yīng)用程序或測試 testClasses 任務(wù)執(zhí)行的任務(wù):


現(xiàn)在,當(dāng)您運(yùn)行測試或啟動應(yīng)用程序時,Micronaut 將在編譯時生成類。

或者,您可以將 IntelliJ 構(gòu)建/運(yùn)行操作完全委托給 Gradle:


使用 Gradle 和 Kapt 進(jìn)行增量注釋處理

要使用 Kapt 啟用 Gradle 增量注釋處理,必須將在使用 Gradle 進(jìn)行增量注釋處理中指定的參數(shù)發(fā)送到 Kapt。

以下示例演示了如何為您在 com.example 和 io.example 包下定義的注釋啟用和配置增量注釋處理:

Enabling Incremental Annotation Processing in Kapt

kapt {
    arguments {
        arg("micronaut.processing.incremental", true)
        arg("micronaut.processing.annotations", "com.example.*,io.example.*")
    }
}

如果您不為您的自定義注釋啟用處理,它們將被 Micronaut 忽略,這可能會破壞您的應(yīng)用程序。

Kotlin 和 AOP 建議

Micronaut 提供了一個不使用反射的編譯時 AOP API。當(dāng)您使用任何 Micronaut AOP Advice 時,它??會在編譯時創(chuàng)建一個子類來提供 AOP 行為。這可能是個問題,因?yàn)?nbsp;Kotlin 類默認(rèn)是最終的。如果應(yīng)用程序是使用 Micronaut CLI 創(chuàng)建的,則 Kotlin 全開放插件已配置為在使用 AOP 注釋時自動更改類以打開。要自己配置它,請將 Around 類添加到支持的注釋列表中。

如果您不想或不能使用全開放插件,則必須聲明使用 AOP 注釋注釋的類是開放的:

import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.HttpStatus
import io.micronaut.validation.Validated
import javax.validation.constraints.NotBlank

@Validated
@Controller("/email")
open class EmailController { (1)

    @Get("/send")
    fun index(@NotBlank recipient: String, (1)
              @NotBlank subject: String): HttpStatus {
        return HttpStatus.OK
    }
}
  1. 如果使用@Validated AOP Advice,則需要在類和方法級別使用open。

全開放插件不處理方法。如果在方法上聲明 AOP 注釋,則必須手動將其聲明為打開。

Kotlin 和保留參數(shù)名稱

與 Java 一樣,使用 Kotlin 時,方法參數(shù)的參數(shù)名稱數(shù)據(jù)不會在編譯時保留。如果您沒有顯式定義參數(shù)名稱并依賴于已編譯的外部 JAR,這對 Micronaut 來說可能是個問題。

要使用 Kotlin 保留參數(shù)名稱數(shù)據(jù),請在 build.gradle 中將 javaParameters 選項(xiàng)設(shè)置為 true:

configuration in Gradle

compileTestKotlin {
    kotlinOptions {
        jvmTarget = '1.8'
        javaParameters = true
    }
}

如果您使用帶有默認(rèn)方法的接口,請?zhí)砑?nbsp;freeCompilerArgs = ["-Xjvm-default=all"] 以便 Micronaut 識別它們。

或者,如果使用 Maven,則相應(yīng)地配置 Micronaut Maven 插件:

configuration in Maven

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- ... -->
  <build>
    <plugins>
      <!-- ... -->
      <plugin>
        <artifactId>kotlin-maven-plugin</artifactId>
        <groupId>org.jetbrains.kotlin</groupId>
        <configuration>
            <javaParameters>true</javaParameters>
            <!-- ... -->
        </configuration>
        <!-- ... -->
      </plugin>
      <!-- ... -->
    </plugins>
  </build>
</project>

協(xié)程支持

Kotlin 協(xié)程允許您使用命令式代碼創(chuàng)建異步應(yīng)用程序。一個 Micronaut 控制器動作可以是一個掛起函數(shù):

  1. 該函數(shù)被標(biāo)記為掛起,但實(shí)際上它不會被掛起。

  2. 該函數(shù)被標(biāo)記為掛起。

  3. 調(diào)用延遲以確保掛起函數(shù)并從不同的線程返回響應(yīng)。

  4. 當(dāng)我們只想返回一個狀態(tài)時,suspend 函數(shù)也可以工作。

您還可以將 Flow 類型用于流式傳輸服務(wù)器和客戶端。流式控制器可以返回 Flow,例如:

  1. 定義了生成 application/x-json-stream 的方法 streamHeadlinesWithFlow

  2. Flow是使用flow創(chuàng)建的

  3. 此流發(fā)出 100 條消息

  4. 使用 emit suspend 函數(shù)進(jìn)行發(fā)射

  5. 消息之間有一秒的延遲

流媒體客戶端可以簡單地返回一個 Flow,例如:

  1. @Get 方法定義為處理 APPLICATION_JSON_STREAM 類型的響應(yīng)

  2. 返回類型是 Flow

協(xié)程跟蹤上下文傳播

Micronaut支持跟蹤上下文的傳播。如果你從控制器動作一直到所有的服務(wù)都使用掛起函數(shù),你不需要做任何特別的事情。然而,當(dāng)你在一個普通的函數(shù)中創(chuàng)建了coroutines時,跟蹤傳播不會自動發(fā)生。你必須使用HttpCoroutineContextFactory<CoroutineTracingDispatcher>來創(chuàng)建一個新的CoroutineTracingDispatcher并將其作為CoroutineContext使用。

下面的例子顯示了這可能是什么樣子的。

@Controller
class SimpleController(
    private val coroutineTracingDispatcherFactory: HttpCoroutineContextFactory<CoroutineTracingDispatcher>
) {
    @Get("/runParallelly")
    fun runParallelly(): String = runBlocking {
        val a = async(Dispatchers.Default + coroutineTracingDispatcherFactory.create()) {
            val traceId = MDC.get("traceId")
            println("$traceId: Calculating sth...")
            calculateSth()
        }
        val b = async(Dispatchers.Default + coroutineTracingDispatcherFactory.create()) {
            val traceId = MDC.get("traceId")
            println("$traceId: Calculating sth else...")
            calculateSthElse()
        }

        a.await() + b.await()
    }
}

反應(yīng)性上下文傳播

Micronaut 支持從 Reactor 上下文到協(xié)程上下文的上下文傳播。要啟用此傳播,您需要包含以下依賴項(xiàng):

 Gradle Maven 
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
<dependency>
    <groupId>org.jetbrains.kotlinx</groupId>
    <artifactId>kotlinx-coroutines-reactor</artifactId>
</dependency>

有關(guān)如何使用該庫的更多詳細(xì)信息,您可以在官方文檔中找到。

以下示例顯示了如何將 Reactor 上下文從 HTTP 過濾器傳播到控制器的協(xié)程:

通過從協(xié)程上下文中檢索 ReactorContext 來訪問 Reactor 上下文:

可以使用協(xié)程 Reactor 集成來使用掛起函數(shù)創(chuàng)建過濾器:


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號