使用SparkJava和Graal的本机微服务
使用SparkJava編寫(xiě)的微服務(wù)只是使用標(biāo)準(zhǔn)Java庫(kù)的普通Java代碼。 沒(méi)有注釋魔術(shù),只有代碼。 這種簡(jiǎn)單的編程風(fēng)格的優(yōu)點(diǎn)在于,它很簡(jiǎn)單。 非常簡(jiǎn)單,以至于Graal本機(jī)編譯器無(wú)需閃爍就可以對(duì)其進(jìn)行編譯 ,這在例如Spring之類(lèi)的更復(fù)雜的框架中目前非常困難。
SparkJava / Graal組合本身就很有趣,人們對(duì)此的體驗(yàn)也開(kāi)始 出現(xiàn) 。 此外,作為Java庫(kù),應(yīng)該可以從其他基于JVM的語(yǔ)言中使用它,而我想知道Graal將如何應(yīng)對(duì)。 實(shí)際上,事實(shí)證明這很簡(jiǎn)單,在本文中,我們將看到為Java,Kotlin甚至Clojure構(gòu)建本機(jī)微服務(wù)二進(jìn)制文件非常容易。
入門(mén)
如果您還沒(méi)接觸過(guò)Graal,我建議您訪(fǎng)問(wèn)他們的網(wǎng)站 ,看看它提供了什么。 在這里,我們使用的是本機(jī)編譯功能,但實(shí)際上這只是表面。
要首先使用Graal,您需要安裝最新版本的Graal SDK。 撰寫(xiě)本文時(shí)為1.0.0-rc9 。 我使用SdkMan做到了 :
sdk install java 1.0.0-rc9-graal從那時(shí)起
sdk use java 1.0.0-rc9-graal然后創(chuàng)建一個(gè)基本的Gradle項(xiàng)目并添加最小依賴(lài)項(xiàng):
dependencies {compile "com.sparkjava:spark-core:2.7.2"compile "org.slf4j:slf4j-simple:1.7.13" }(我假設(shè)您已經(jīng)熟悉Gradle,如果愿意的話(huà),可以使用Maven進(jìn)行 。請(qǐng)注意,選擇的Slf4j實(shí)現(xiàn)與SparkJava所需的版本匹配非常重要。)
對(duì)于SparkJava,微服務(wù)端點(diǎn)本質(zhì)上是lambda表達(dá)式形式的路徑或回調(diào)之間的綁定或route 。 這是我們將用作基礎(chǔ)的標(biāo)準(zhǔn)“ hello world”示例。 當(dāng)然,現(xiàn)實(shí)世界中的服務(wù)將利用請(qǐng)求和響應(yīng)對(duì)象。 請(qǐng)參閱文檔以獲取更多詳細(xì)信息。
import static spark.Spark.*;public class HelloWorld {public static void main(String[] args) {get("/sayHello", (req, res) -> "Hello world!");} }要將其作為命令行程序運(yùn)行,將所有依賴(lài)項(xiàng)一起復(fù)制到同一目錄中非常方便。 我們也可以使用Gradle做到這一點(diǎn)。
task copyDependencies(type: Copy) {from configurations.defaultinto 'build/libs'shouldRunAfter jar }assemble.dependsOn copyDependencies生成服務(wù)并運(yùn)行它以檢查其是否有效。
> ./gradlew clean assemble> java -cp "build/libs/*" HelloWorld ... [Thread-0] INFO org.eclipse.jetty.server.Server - Started @363ms> curl localhost:4567/sayHello Hello World!讓我們使用Graal將其編譯為本地二進(jìn)制文件。 幸運(yùn)的是,該命令與java命令非常相似:
> native-image -cp "build/libs/*" HelloWorld ... Build on Server(pid: 31197, port: 52737)* [helloworld:31197] classlist: 2,142.65 ms [helloworld:31197] (cap): 2,154.21 ms ... ... [helloworld:31197] write: 443.13 ms [helloworld:31197] [total]: 56,525.52 ms現(xiàn)在,我們應(yīng)該在當(dāng)前目錄中擁有本機(jī)二進(jìn)制文件。 讓我們運(yùn)行它:
> ./helloworld ... [Thread-2] INFO org.eclipse.jetty.server.Server - Started @2ms> curl localhost:4567/sayHello Hello World!可執(zhí)行文件為14Mb,但看該啟動(dòng)時(shí)間為2ms ,基本上是瞬時(shí)的! 在內(nèi)存方面,過(guò)多地關(guān)注top并不是明智的選擇,但是很明顯,從運(yùn)行時(shí)刪除JVM具有其優(yōu)勢(shì)。 這在部署大量獨(dú)立進(jìn)程的微服務(wù)系統(tǒng)中尤其重要。
Kotlin呢?
Kotlin是一種JVM語(yǔ)言,正在Swift發(fā)展并且并非沒(méi)有道理。 它結(jié)合了功能樣式和OO功能,無(wú)縫的Java互操作性和簡(jiǎn)潔的語(yǔ)法,使其成為通用的良好語(yǔ)言,并且是Java的明顯替代。 首先要使用Kotlin構(gòu)建我們的服務(wù),我們將Kotlin庫(kù)依賴(lài)項(xiàng)添加到Gradle(撰寫(xiě)本文時(shí)版本為v1.3.10)。
dependencies { ...compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.10" }并使用Kotlin編譯器插件。
plugins {id 'org.jetbrains.kotlin.jvm' version '1.3.10' }使用Kotlin,我們荒謬的簡(jiǎn)單微服務(wù)變得更加簡(jiǎn)單。
import spark.Spark.*fun main(args: Array<String>) {get("/sayHello") { req, res -> "Hello World!" } }生成服務(wù)并運(yùn)行它以檢查其是否有效。
> ./gradlew clean assemble> java -cp "build/libs/*" HelloWorldKt ... [Thread-0] INFO org.eclipse.jetty.server.Server - Started @363ms> curl localhost:4567/sayHello Hello World!讓我們本地編譯它。 因?yàn)樗?Java,所以命令幾乎與Java版本相同(Kotlin編譯器會(huì)自動(dòng)將Kt后綴添加到生成的類(lèi)中)。
> native-image -cp "build/libs/*" HelloWorldKt Build on Server(pid: 53242, port: 51191) [helloworldkt:53242] classlist: 783.03 ms [helloworldkt:53242] (cap): 2,139.45 ms ... [helloworldkt:53242] write: 591.88 ms [helloworldkt:53242] [total]: 53,074.15 ms并運(yùn)行它:
> ./helloworldkt ... [Thread-2] INFO org.eclipse.jetty.server.Server - Started @2ms> curl localhost:4567/sayHello Hello World!可執(zhí)行文件的大小和啟動(dòng)速度幾乎與Java版本相同,這是可以預(yù)期的,因?yàn)樗鼘?shí)質(zhì)上是相同的代碼。
這是一個(gè)基本示例,但Kotlin的實(shí)現(xiàn)簡(jiǎn)化 , SparkJava的簡(jiǎn)化 實(shí)現(xiàn) 微服務(wù)和Graal的簡(jiǎn)化部署相結(jié)合,是微服務(wù)開(kāi)發(fā)非常有吸引力的主張。
盡管如此,除了更好的語(yǔ)法外,Kotlin與Java非常相似。 我們還可以使用其他JVM語(yǔ)言,這些語(yǔ)言可能會(huì)進(jìn)一步推動(dòng)Graal。
需要Clojure
使用Clojure構(gòu)建微服務(wù)是一個(gè)有趣的想法。 服務(wù)本質(zhì)上是自然的功能,實(shí)際上服務(wù)是一種功能,語(yǔ)言的動(dòng)態(tài)特性可能使其成為某些以數(shù)據(jù)為中心的情況的理想選擇。
而不是使用Gradle,我們將從一個(gè)新的Leiningen項(xiàng)目開(kāi)始:
lein new hello-clojure依賴(lài)關(guān)系放在main project.clj文件中,以及我們將用來(lái)啟動(dòng)服務(wù)器的主類(lèi)的名稱(chēng)。
:dependencies [[org.clojure/clojure "1.9.0"][com.sparkjava/spark-core "2.7.2"][org.slf4j/slf4j-simple "1.7.13"]]:main hello_clojure.core)Clojure可與Java互操作,但程度不及Kotlin。 為了克服這些差異,我編寫(xiě)了一些適配器,以允許慣用的clojure代碼使用SparkJava的類(lèi)。
(ns hello_clojure.core(:gen-class)(:import (spark Spark Response Request Route)))(defn route [handler](reify Route(handle [_ ^Request request ^Response response](handler request response))))(defn get [endpoint routefn](Spark/get endpoint (route routefn)))(我后來(lái)發(fā)現(xiàn)了一篇不錯(cuò)的文章 ,其中提供了使用Clojure和SparkJava的完整服務(wù)。它們的適配器比我的適配器稍好,因此我在后面的文章中結(jié)合了一些想法。)
然后,我們準(zhǔn)備創(chuàng)建從main方法執(zhí)行的控制器,以便可以從命令行輕松調(diào)用它。 還要注意,在上面我們使用gen-class指令來(lái)確保在清單中指定了主類(lèi):
(defn -main [](get "/sayHello" (fn [req resp] "Hello World!!")))為了簡(jiǎn)化服務(wù)的生成,我們可以使用Leiningen構(gòu)建一個(gè)自包含的jar。
> lein clean && lein uberjar和以前一樣,我們首先檢查該服務(wù)是否可以正常運(yùn)行Java:
$ java -cp target/hello-clojure-0.1.0-SNAPSHOT-standalone.jar hello_clojure.core ... [Thread-0] INFO org.eclipse.jetty.server.Server - Started @1033ms> curl localhost:4567/sayHello Hello World!編譯為本地映像就像使用Java和Kotlin的先前示例一樣簡(jiǎn)單。
> native-image -cp target/hello-clojure-0.1.0-SNAPSHOT-standalone.jar hello_clojure.core Build on Server(pid: 35646, port: 53994)* [hello_clojure.core:35646] classlist: 2,704.82 ms [hello_clojure.core:35646] (cap): 909.58 ms ... [hello_clojure.core:35646] write: 647.23 ms [hello_clojure.core:35646] [total]: 54,900.61 ms并運(yùn)行它:
> ./helloworld_clojure ... [Thread-2] INFO org.eclipse.jetty.server.Server - Started @2ms> curl localhost:4567/sayHello Hello World!本地二進(jìn)制文件再次大約為15M,并且啟動(dòng)時(shí)間幾乎是瞬時(shí)的。
結(jié)論
將Graal與其他基于JVM的語(yǔ)言結(jié)合使用是一個(gè)非常誘人的主張,值得進(jìn)一步研究,但是我確實(shí)對(duì)生產(chǎn)用途存在一些擔(dān)憂(yōu)。 主要是如果出現(xiàn)問(wèn)題,公共領(lǐng)域中幾乎沒(méi)有信息可以為您提供幫助,而純Java之外的信息則更少。 另一方面,這些都是開(kāi)源項(xiàng)目,所以什么都沒(méi)有隱藏:)
另一個(gè)限制是,許多庫(kù)根本無(wú)法與Graal一起使用。 這并不是完全消極的,因?yàn)樗鼤?huì)鼓勵(lì)我們回到簡(jiǎn)單的編碼實(shí)踐中,但是您可能會(huì)遇到無(wú)法更改的依賴(lài)關(guān)系,這可能會(huì)引起很大的麻煩。 我認(rèn)為最初的主要缺點(diǎn)是反射驅(qū)動(dòng)的映射,無(wú)論是序列化還是ORM品種。 為了使許多庫(kù)和框架與Graal 兼容 ,已經(jīng)做了很多工作,但是還處于初期。
第三,主要是實(shí)際的考慮是對(duì)本機(jī)映像的編譯非常慢。 即使是這個(gè)非常簡(jiǎn)單的示例,也幾乎需要花費(fèi)一分鐘的時(shí)間來(lái)構(gòu)建。 當(dāng)然,您可以?xún)H將開(kāi)發(fā)編譯為字節(jié)碼,但是兼容性問(wèn)題可能會(huì)消失。 持續(xù)的構(gòu)建流程和全面的測(cè)試將是減輕這種風(fēng)險(xiǎn)的一種方法。
顯然,要使它成為一個(gè)功能齊全的服務(wù)還有很多工作要做,并且在投入生產(chǎn)使用之前要進(jìn)行適當(dāng)?shù)目紤],但是如果我們選擇繼續(xù)使用簡(jiǎn)單的代碼,那么問(wèn)題將被最小化。
翻譯自: https://www.javacodegeeks.com/2019/01/native-microservices-sparkjava-graal.html
總結(jié)
以上是生活随笔為你收集整理的使用SparkJava和Graal的本机微服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: 4个月是什么字 4个月应该是什么字
- 下一篇: 苹果7手机怎么取消开机密码
