在第 4 天的文章,有提到了 Quarkus 提供了 Dev UI. 其中自帶的 sample hello service 是 66 分。我們可以直上 Kotlin coroutines 的魔力。讓 blocking function 直接變成 Non-blocking function。 只要加上那個 suspend keyword
suspend fun hello() = "Hello from RESTEasy Reactive" // Made service non-blocking
這裡加上 suspend 就可以把 request 轉到 Vert.x 的 worker thread
Writer 有得分表示在 build time 時有明確決定要用哪個 Serializer。這裡我們可看到是 io.quarkus.kotlin.serialization.KotlinSerializationMessageBodyWriter。用的是 Kotlinx Serialization。這是因為我們一開始選用了 quarkus-resteasy-reactive-kotlin-serialization。
RESYEasy 在 serialization 這塊還有 Jackson, JsonB 的實現,在 project 中要擇一引入。這次我們要貫徹用 Kotlin 的意志,選用當然是 kotlinx 的 Serialization.
表示我們用一個 instance 服務所有的 request。這塊也是 Day8 or Day9 會討論 Quarkus Reactive
RESTEasy Reactive 為 JAX-RS 的新的實現。背後利用了 Vert.x 這個 reactive 的 framework 並與 Quarkus 強整合,所以也是會把很多工作在 build time 作掉。
JAX-RS 是 RESTful 公版標準,所以在這裡的實作上跟 Spring Boot 使用上幾乎是無痛轉移 @GET, @POST, @DELETE ....,而且會有很好的 performance (Non-Blocking)。
接下來用 Quarkus 實作一個簡易 Film 的 RESTful Service. 我們會作一個電影資訊查詢的 Service。
在 project folder 輸入
quarkus create app tw.brandy.ironman:filmServiceQK --extension=kotlin,quarkus-resteasy-reactive-kotlin-serialization
用 mobaxterm 打開 IntelliJ, 並且打開剛剛建立的專案
雖然 Quarkus 對於 Kotlin 的支援不錯,有些眉角還是要注意一下。Kotlin Serialization 是在build 會作事。所以要加上支援。
找到 quarkus-resteasy-reactive-kotlin-serialization
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-kotlin-serialization</artifactId>
</dependency>
<!-- 在其後面加上 -->
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<version>0.4.0</version>
</dependency>
找到 kotlin-maven-allopen 在其後加上
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-serialization</artifactId>
<version>${kotlin.version}</version>
</dependency>
compilerPulgins 修改
<compilerPlugins>
<plugin>all-open</plugin>
<plugin>kotlinx-serialization</plugin>
</compilerPlugins>
這裡要開始新增一些 class。總共有三個kt如圖
@Serializable
data class Film(
val title: String,
val episodeID: Int,
val director: String,
@Serializable(LocalDateComponentSerializer::class)
val releaseDate: LocalDate
)
這裡是拿 Quarkus Java Sample 來改。可以看到兩相比較簡單很多。 Film 的新增也演示的 Kotlin 的三種作法。
@ApplicationScoped // Quarkus 裡 bean 的宣告方法
class FilmService {
private val films: MutableList<Film> = ArrayList<Film>()
init {
films.apply {
add(
Film(
episodeID = 4,
title = "A New Hope",
director = "George Lucas",
releaseDate = LocalDate.parse("1977-05-25")
)
)
Film(
episodeID = 5,
title = "The Empire Strikes Back",
director = "George Lucas",
releaseDate = LocalDate.parse("1980-05-21")
).let { add(it) }
Film(
episodeID = 5,
title = "Return Of The Jedi",
director = "George Lucas",
releaseDate = LocalDate.parse("1983-05-25")
).let(::add)
}
}
fun getAllFilms() = films.toList()
fun getFilm(id: Int) = films.first { id == it.episodeID }
}
@Path("/films")
class FilmResource(val filmService: FilmService) {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
suspend fun getAllFilms() = filmService.getAllFilms()
@GET
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
suspend fun getFilmById(id: Int) = filmService.getFilm(id)
}
在 IntelliJ 中我們可以在右上加入 quarkus:dev 的 maven 啟動。
加入後,以後就可以按那個綠色的 play 啟動。打開 http://localhost:8080/q/dev/io.quarkus.quarkus-resteasy-reactive/scores 可以看到我們三個 Endpoint 都是 100 分
http://localhost:8080/films
http://localhost:8080/films/5
可以看到RESTful Service 已順利運作
目前我們作到的是 Endpoint 端的 non-blocking。然而不只是 Endpoint, 在後端接 DB 或是其他 Service 也是要這種 non-blocking 的機制來減少 Resource 的使用。所以明天我們來接上 Mongodb 吧 (順利的話)