给新手看的 Micronaut 入门教程,10 分钟写出一个 Micronaut 程序
以下內(nèi)容均選自 Micronaut 入門實戰(zhàn):基于 JVM 的微服務(wù)框架 。
Micronaut是什么?
Micronaut 是一個現(xiàn)代化的基于 JVM 的全棧框架,用于構(gòu)建模塊化且易于測試的微服務(wù)或無服務(wù)程序。
同時,Micronaut 使用 Netty,并且對響應(yīng)式編程提供一流的支持。對于 JVM 領(lǐng)域的全棧框架來說,Micronaut 是一個非常有前途的新成員。
Micronaut 旨在提供構(gòu)建微服務(wù)所需要的一切工具,包含:
- 依賴注入(DI)和控制翻轉(zhuǎn)(IoC)。
- 合理的默認(rèn)值和自動配置。
- 配置及配置共享。
- 服務(wù)發(fā)現(xiàn)。
- HTTP 路由。
- 具有負(fù)載均衡的 HTTP 客戶端。
同時,Micronaut 也致力于避免像 Spring、Spring Boot 和 Grails 中的弊端,通過:
- 快速啟動。
- 減少內(nèi)存占用。
- 極少的反射使用。
- 極少的代理使用。
- 簡單的單元測試。
在以前,像 Spring 和 Grails 這些框架并不是被設(shè)計來在 server-less、安卓 Apps 或低內(nèi)存占用的場景中運行。相反,Micronaut 則是為此而生。
Micronaut 通過使用 Java 的 annotation processor 來實現(xiàn)以上功能,annotation processor 可以在任何支持其的 JVM 上使用,包括在使用 Netty 構(gòu)建的 HTTP Server 和 Client 上。
為了提供和 Spring 以及 Grails 相似的編程模型,這些 annotation processor 預(yù)編譯了必要的元數(shù)據(jù)(Metadata)來進(jìn)行依賴注入、定義 AOP 代理以及配置你的應(yīng)用程序,使其能夠在微服務(wù)環(huán)境中運行。
創(chuàng)建第一個 Micronaut 程序
接下來將要創(chuàng)建我們的第一個 Micronaut 程序,內(nèi)容包括提供一個 /hello API 接口以及相應(yīng)的測試類。
然后,使用 GraalVM 提供的 native image 將程序構(gòu)建為一個可運行的二進(jìn)制文件。
▲創(chuàng)建程序
Micronaut 提供了一個 CLI(Command Line Interface,命令行接口)讓我們可以方便快速地創(chuàng)建一個 Micronaut 程序。這個 CLI 包含了用于生成指定類型項目的命令,可以選擇項目的構(gòu)建工具、測試框架甚至是程序使用的語言。同時,它也提供了生成代碼(如:Controller、Client Interface 和 Serverless Functions)的命令。詳情可參考官網(wǎng)文檔 Micronaut CLI。
下面我們來使用 Micronaut CLI 來創(chuàng)建程序,在實驗樓 WebIDE 終端中執(zhí)行以下命令:
mn create-app example.micronaut.complete- mn 用于調(diào)用 Micronaut 的 CLI。
- create-app 即表明要創(chuàng)建一個 Micronaut 程序。默認(rèn)情況下,create-app 會創(chuàng)建一個 Java Micronaut 程序,并使用 Gradle 構(gòu)建系統(tǒng)。但你也可以使用其他的構(gòu)建工具(如:Maven)和語言(如:Groovy 和 Kotlin)。
- example.micronaut.complete 作為參數(shù),指定了程序的默認(rèn)包名和程序名,最后一個 . 號前面的內(nèi)容將作為包名(此處即:example.micronaut),后面的內(nèi)容將作為文件夾名(此處即:complete)。
執(zhí)行后的結(jié)果如下:
注意:以后的實驗中,如無特殊說明,都將在 /home/project 目錄下創(chuàng)建程序。
Application
Application.java 文件被用于使用 Gradle 或部署時運行程序,你也可以通過直接執(zhí)行該類的 main() 函數(shù)來直接運行程序。其代碼如下:
package example.micronaut;import io.micronaut.runtime.Micronaut;public class Application {public static void main(String[] args) {Micronaut.run(Application.class);} }▲編寫代碼
Controller
為了創(chuàng)建一個能夠響應(yīng)并返回 “Hello World” 的微服務(wù),首先我們需要創(chuàng)建一個 Controller。
在 src/main/java/example/micronaut 目錄下創(chuàng)建 HelloController.java 文件,編寫代碼如下:
package example.micronaut;import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Produces;@Controller("/hello") // ① public class HelloController {@Get // ②@Produces(MediaType.TEXT_PLAIN) // ③public String index() {return "Hello World"; // ④} }為了便于查看,我們在程序中用數(shù)字來標(biāo)注,然后在下方給予解釋,序號一一對應(yīng)。
注:后續(xù)實驗中,如無特殊說明的情況下,在編寫程序時,默認(rèn)使用 src/main/java/example/micronaut 作為目錄。
如:創(chuàng)建 HelloController.java 文件。
即:在 src/main/java/example/micronaut 目錄下創(chuàng)建 HelloController.java 文件。
Test
接著我們創(chuàng)建一個 Junit 的測試來驗證當(dāng)我們對 /hello 進(jìn)行一次 GET 請求時,是否會得到 Hello World 作為響應(yīng)。
在 src/test/java/example/micronaut 目錄下創(chuàng)建 HelloControllerTest.java 文件,編寫代碼如下:
package example.micronaut;import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull;import io.micronaut.http.HttpRequest; import io.micronaut.http.client.RxHttpClient; import io.micronaut.http.client.annotation.Client; import io.micronaut.test.annotation.MicronautTest; import org.junit.jupiter.api.Test;import javax.inject.Inject;@MicronautTest // ① public class HelloControllerTest {@Inject@Client("/")RxHttpClient client; // ②@Testpublic void testHello() {HttpRequest<String> request = HttpRequest.GET("/hello"); // ③String body = client.toBlocking().retrieve(request);assertNotNull(body);assertEquals("Hello World", body);} }▲運行程序
測試程序
在運行程序之前,最好的做法是先進(jìn)行測試。在實驗樓 WebIDE 終端中執(zhí)行以下命令進(jìn)行測試。
# 進(jìn)入項目的目錄 cd /home/project/complete # 測試 ./gradlew test執(zhí)行的結(jié)果如下所示。
運行程序
在實驗樓 WebIDE 終端中使用以下命令可以讓程序在 8080 端口運行。
./gradlew run當(dāng)控制臺顯示內(nèi)容如下時,表明程序已經(jīng)處于運行狀態(tài)中。
接著,打開 Web 服務(wù),在地址欄末尾添加 /hello 來訪問我們的 /hello API。結(jié)果如下。
如果要停止程序運行,按下 Ctrl + C 即可。
▲使用 GraalVM 生成 Native Image
我們將使用 GraalVM,一個多語言可嵌入的虛擬機,來為我們的程序生成一個 Native Image(本地鏡像)。
Native Images 用到了 GraalVM 的 ahead-of-time 技術(shù)為基于 JVM 的應(yīng)用改善啟動時間并減少內(nèi)存占用。
▲Micronaut + GraalVM 的變化
Micronaut 本身不依賴反射或動態(tài)類加載,所以可以很好地適配 GraalVM Native。
首先,添加 Micronaut Graal 的注解處理器來用于生成 native-image 工具要使用的 reflection-config.json 元數(shù)據(jù)。
打開項目的 build.gradle 文件,追加以下依賴。
dependencies {annotationProcessor "io.micronaut:micronaut-graal" }GraalVM Native Image 允許我們預(yù)編譯(ahead-of-time compile)Java 代碼來生成一個叫做本地鏡像(Native Image)的獨立可執(zhí)行文件。這個可執(zhí)行文件包含了程序本身、庫和 JDK,且不運行在 Java 虛擬機上,但在另一個叫做 SVM(Substrate VM) 的虛擬機中包含了必要的組件,如內(nèi)存管理和線程調(diào)度。SVM 是運行時組件的一個統(tǒng)稱,這些組件包括 deoptimizer_,_garbage collector 和 thread scheduling 等等。這使得生成的程序會比使用 Java 虛擬機時擁有更快的啟動速度以及更低的內(nèi)存占用。
我們需要在 build.gradle 中添加一個 SVM 的依賴:
dependencies {compileOnly "org.graalvm.nativeimage:svm:19.3.0" }為了使構(gòu)建鏡像更加簡潔,我們需要創(chuàng)建一個 native-image.properties 文件。標(biāo)準(zhǔn)做法是使用 sra/main/resources/META-INF/native-image 文件夾并在該文件夾下創(chuàng)建一個遵循 Maven 坐標(biāo)來描述程序的文件夾。例如,我們的項目名設(shè)為 micronautguide,則應(yīng)創(chuàng)建 example.micronaut/micronautguide 文件夾。下面通過命令行的模式來進(jìn)行創(chuàng)建。
# 進(jìn)入項目目錄 cd /home/project/complete # 創(chuàng)建文件夾 mkdir -p src/main/resources/META-INF/native-image/example.micronaut/micronautguide # 創(chuàng)建文件 touch src/main/resources/META-INF/native-image/example.micronaut/micronautguide/native-image.properties然后,在 native-image.properties 文件中編寫以下內(nèi)容。
Args = -H:IncludeResources=logback.xml|application.yml \-H:Name=micronautguide \-H:Class=example.micronaut.Application- -H:IncludeResources:參數(shù)允許我們設(shè)置包括哪些靜態(tài)資源,可以使用正則表達(dá)式。這里為 logback.xml 和 application.yml。
- -H:Name:參與指定了生成的 Native Image 的名字,這里為 micronautguide。
- -H:Class:參數(shù)指定了程序的入口(定義了 main() 方法的類)。這里為 example.micronaut.Application,即 Application.java 文件中的 main() 方法。
▲生成 Native Image
為了生成 Native Image,我們需要先生成程序的 FAT JAR。
在實驗樓 WebIDE 終端中執(zhí)行以下命令。
./gradlew assemble執(zhí)行后的結(jié)果如下。
然后開始生成 Native Image,生成鏡像的命令如下。
native-image --no-server -cp build/libs/complete-0.1-all.jar- -no-server 選項表明不使用基于 server 的鏡像來構(gòu)建。
重要提示
構(gòu)建 Native Image 的開銷較大,由于實驗樓的環(huán)境限制,標(biāo)準(zhǔn)環(huán)境下會因內(nèi)存不足而失敗。所以我們建議跳過構(gòu)建鏡像的步驟,下載我們提前構(gòu)建的 Native Image。同學(xué)可以在自己電腦上進(jìn)行嘗試。
在實驗樓 WebIDE 終端中執(zhí)行以下命令下載構(gòu)建好的鏡像。
# 進(jìn)入項目目錄 cd /home/project/complete # 下載鏡像 wget https://labfile.oss.aliyuncs.com/courses/1511/micronautguide # 為文件添加可執(zhí)行權(quán)限 chmod +x ./micronautguide這里提供一下生成鏡像時的控制臺輸出截圖,可以看到在 1 核 4 G 的環(huán)境中花了 20 分鐘的時間。
最后,讓我們來體驗一下生成的鏡像的優(yōu)勢。在實驗樓 WebIDE 中執(zhí)行以下命令運行程序。
./micronautguide -Xmx68m執(zhí)行結(jié)果如下。
可以看到程序比起之前啟動的速度明顯提升了不少。新建一個控制臺(菜單欄 -> Terminal -> New Terminal),執(zhí)行以下命令來訪問 /hello API 接口。
curl localhost:8080/hello執(zhí)行結(jié)果如下。
你的第一個程序就完成啦,可在 Micronaut 入門實戰(zhàn):基于 JVM 的微服務(wù)框架 查看本節(jié)實驗的源碼并繼續(xù)學(xué)習(xí)后面的內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的给新手看的 Micronaut 入门教程,10 分钟写出一个 Micronaut 程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot 实战:如何从零开发
- 下一篇: 6 个前端开发必备工具,提高你的生产力