Vert.xで表されるKotlinの非同期代替

KotlinはAndroid開発者の間で人気のあるツールですが、ご存知のように、これが唯一のアプリケーションではありません。 そのため、単純なWebサービスを作成することにしたとき、Kotlinだけで作成するのが妥当と思われました。







Spring Frameworkが唯一のオプションではないことがわかりました。 別の強力な非同期の代替手段-Vert.xがあります。これは、何らかの理由でKotlinのコンテキストではめったに言及されません。 このタンデムについては、この記事で説明します。







Vert.x + Kotlin







やる気



プロジェクトを開始して、不可能を望みました。プロトタイプをすばやく作成し、Herokuでホストするだけです。必要に応じて、プロトタイプを最初から書き直さずに本格的なプロジェクトに拡張します。







優秀なブロガーの公式ドキュメントと例は、将来のバージョンでのKotlinの優れた互換性とネイティブサポートを引用して、満場一致でSpring Frameworkを推奨しました。 しかし、そう思う場合、特別な互換性が必要ですか? この言語はすでにJavaに対応しているため、フレームワークを選択し、標準ライブラリをインポートして実行します。







Vert.xとは何ですか?



Vert.xは、Web用のモジュールを備えた、あらゆるアプリケーション向けの非同期イベント指向フレームワークです。 アーキテクチャはNode.jsに類似しているため、プロジェクトは2011年に「Node.x」という名前で始まり、作成者のTim Foxはそれを危険であると考え、「node」(「node」および「頂点は「グラフ理論のノード」です。 JavaScriptに制限されているNode.jsとは異なり、Vert.xはJava、Groovy、Ruby、Ceylonもサポートしています(過去にPython、Scala、Clojureもサポートしていました)。







次のVert.xオプションに興味がありました。









このサイトにはすでにそれに関する良い記事があったので、これでフレームワーク自体の説明は完了です。 私の仕事は、Kotlinでこれらすべてのアメニティをどのように使用できるかを示すことです。







挑戦する



島(たとえば、 Kotlin )およびこれらの島が位置する国のリストをRESTモデルに従ってJSON形式で返すWebサービスが必要だとします。









これは特に便利なWebサービスではありませんが、フレームワークを実証するのに十分であり、プロジェクトやその他のライブラリの不必要な詳細を避け、メイントピックだけをそらすことができます。







データ



Webサービスが返すデータから始めましょう。 必要なモデルは、 Island



Country



2つだけです。







 data class Island(val name: String, val country: Country) data class Country(val name: String, val code: String)
      
      





Kotlinの日付クラスのおかげで、他に何も心配する必要はありませんequals()



hashCode()



メソッド、getterおよびsetterはすべてこの単純な構造に自動的に接続されます。







次は、データにアクセスするためのIslandDao



です。実際のアプリケーションでは、特定のデータベースへの要求があり、準備されたアイランドを持つ単純な静的配列があります。







 class IslandsDao { companion object { private val MOCK_ISLANDS by lazy { listOf( Island("Kotlin", Country("Russia", "RU")), Island("Stewart Island", Country("New Zealand", "NZ")), Island("Cockatoo Island", Country("Australia", "AU")), Island("Tasmania", Country("Australia", "AU")) ) } } fun fetchIslands() = MOCK_ISLANDS fun fetchCountries(code: String? = null) = MOCK_ISLANDS.map { it.country } .distinct() .filter { code == null || it.code.equals(code, true) } .sortedBy { it.code } }
      
      





メソッドの簡単な概要:









この最小限のDAOは、アプリケーション自体に行くのに十分です。









Vert.xアプリケーションの心臓部は、バーティカルそのものです。 私のファンタジーは悪いので、「MainVerticle」と呼びましょう。







 class MainVerticle : AbstractVerticle()
      
      





まず、DAO用のフィールドを作成することから始めましょう。これは既に上で書いたものです。







 private val dao = IslandsDao()
      
      





ここで重要な部分は、タイプとパスでリクエストを配信するルーターです。 まず、最も単純なルートを分析します。







 private val router = Router.router(vertx).apply { get("/").handler { ctx -> ctx.response().end("Welcome!") } }
      
      





これは、プレーンテキスト「Welcome!」を返すルートGETルートです。







しかし、なぜテキストが必要なのでしょうか? JSONシリアル化オブジェクトの方が良いでしょう。 これを行うには、ユーティリティで拡張endWithJson(Any)



を作成します。これは、「Content-Type」ヘッダーにJSON形式を事前入力し、渡されたオブジェクトをシリアル化することによってのみ要求チェーンを終了します。







 fun HttpServerResponse.endWithJson(obj: Any) { putHeader("Content-Type", "application/json; charset=utf-8").end(Json.encodePrettily(obj)) }
      
      





これで、DAOからデータのリストを取得してJSONとして返すルーターにさらに2、3のルートを追加できます。







 get("/islands").handler { ctx -> val islands = dao.fetchIslands() ctx.response().endWithJson(islands) } get("/countries").handler { ctx -> val countries = dao.fetchCountries() ctx.response().endWithJson(countries) }
      
      





もうおもしろくて便利ですよね?







タスクから、コードで国を検索するルートのみがありました。







 get("/countries/:code").handler { ctx -> val code = ctx.request().getParam("code") val countries = dao.fetchCountries(code) if (countries.isEmpty()) { ctx.fail(404) } else { ctx.response().endWithJson(countries.first()) } }
      
      





すべてが前のものとほとんど同じで、パラメーターのみが追加されました:code



パス自体に:code



HttpServerRequest.getParam(String)



を使用して取得できます)、および成功したend()



に加えて、 fail()



HTTPエラーコードで表示されました国が見つからない場合。







これで、ルーターの準備ができました。 サーバー自体を組み立てるだけです。 確かに、実際よりもはるかに大きく聞こえます。







抽象クラスAbstractVerticle



には、垂直方向の開始時に呼び出されるstart()



メソッドがあります。 ここにWebサーバーを起動する手順を配置します。







 override fun start(startFuture: Future<Void>?) { vertx.createHttpServer() .requestHandler { router.accept(it) } .listen(Integer.getInteger("http.port", 8080)) { result -> if (result.succeeded()) { startFuture?.complete() } else { startFuture?.fail(result.cause()) } } }
      
      





上記のコードは次のことを行います。







  1. 新しいHTTPサーバーを作成します
  2. リクエストをルーターに転送します
  3. パラメーターで指定されたポート(またはデフォルトで8080)を介して要求をリッスンします


これでアプリケーションコードが完成しました。これで構成の魔法です!







構成



構成は、gradleスクリプト「build.gradle」に存在します







 buildscript { ext { kotlin_version = '1.1.0' vertx_version = '3.3.3' } repositories { jcenter() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }
      
      





まず、 buildscript



バージョンとプラグインを設定buildscript



部分です(この場合は1つだけです)。







 plugins { id 'java' id 'application' id 'com.github.johnrengelman.shadow' version '1.2.4' } apply plugin: 'kotlin'
      
      





次に、事前定義済みの組み込みプラグインを使用します。







最初の2つの「java」と「application」は、Javaアプリケーションのスケルトンとして必要であり、これに基づいて私たちはすべて構築しています。







上記の「kotlin」は、Kotlinアプリケーションの設定に関して必要なものすべてです。







ここで「 shadow 」プラグインが使用されるため、作成されたJARは「fat」(「fat jar」)になります。つまり、使用されるすべてのライブラリが含まれます。 これにより、展開が大幅に簡素化されますが、そのためには構成も必要になります。







 shadowJar { baseName = 'app' classifier = 'shadow' manifest { attributes 'Main-Verticle': 'net.gouline.vertxexample.MainVerticle' } mergeServiceFiles { include 'META-INF/services/io.vertx.core.spi.VerticleFactory' } }
      
      





最初の2つのフィールド「baseName」および「classifier」は、出力スクリプトが簡単に見つけられるように、出力JARの名前(つまり、「app-shadow.jar」)を示します。 さらに、前に書いたバーティカルおよび標準のVerticleFactory



へのパスを構成します。







 repositories { jcenter() } dependencies { compile "io.vertx:vertx-core:$vertx_version" compile "io.vertx:vertx-web:$vertx_version" compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" }
      
      





ここで、必要なライブラリを使用します。この場合、必要なライブラリは3つだけです。









 sourceCompatibility = '1.8' mainClassName = 'io.vertx.core.Launcher'
      
      





最後に、Java 8(これはVert.xの最小値)と起動時のメインクラス(組み込みのLauncher)のソース互換性を確立します。







すべて、構成の準備ができました!







組み立てとホスティング



ローカルコンピューターでのビルドは非常に簡単ですgradle shadowJar



実行するgradle shadowJar



、またはWebサーバーにアップロードできるJARファイルをエクスポートするgradle shadowJar



を実行します。







しかし、冒頭で述べたように、Herokuでもすべてが機能するようにしたいと思います。 これを行うには、次の内容の「Procfile」を作成します。







 web: java $JAVA_OPTS -Dhttp.port=$PORT -jar build/libs/app-shadow.jar
      
      





この行は、アプリケーションの実行方法を説明しています。javaを使用して、ポート番号(Heroku自身が決定)と、最後に「build.gradle」で登録したのと同じ「app-shadow.jar」を指定します。







以上です! これで、 Herokuのドキュメントで説明されているように、このアプリケーションをGit remootに完全にアップロードして、結果を楽しむことができます。







おわりに



Kotlin、Vert.x、またはその両方を一緒に試すように誰かを説得したいと思います。 どちらのプロジェクトにも多くのドキュメント(公式およびアマチュア)があるため、より複雑なアプリケーションの作成方法を理解することは難しくありません。







Vert.xのドキュメントにはKotlinのセクションはありませんが、JavaのAPIを使用しているため、ある言語の機能は簡単に別の言語に翻訳されています。 さらに、Javaの例をKotlinクラスにコピーすると、IntelliJ IDEA自体がコードを自動的に変換することを提案します。







プロジェクトのフルバージョンは、GitHubの「vertx-kotlin-example」にあります。これは、すべてのアップデートといくつかの拡張機能でサポートしています。 このバージョンは、ジャンプ後に簡単に起動でき、Herokuにもデプロイされます。







ご清聴ありがとうございました!







参照資料






All Articles