[Java8][Framework] New Next Web Framework 「Jooby」入門 [QuickStart]

2016.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。こむろ@札幌です。札幌へ引っ越してきて2年弱、ようやく車を買ったので今年の夏は道内をうろうろする予定です。

ひとまず手始めに、WORKING!!!寿司で有名な寿司のまつくらへ行く予定であります。

Joobyとは

Java8ネイティブなWeb Application Frameworkのひとつです。

JavaのFrameworkは数多くあり、有名どころでは StrutsSeaser, Spring Framework があります。 *1これらは歴史も長く、開発者に非常に親しまれているため、多くの人が開発に利用したことのある安定したFrameworkです。

既存の古いJava(6や7)での動作もサポートしており、様々の進化を経たJava8以降の機能を全てあますところなく利用し、最大のパフォーマンスを発揮しているとは言いがたい状況です。

試しにSpring Frameworkを確認してみると最小構成の環境は以下のように定義されています。

Minimum requirements

  • JDK 6+ for Spring Framework 4.x
  • JDK 5+ for Spring Framework 3.x

これらの古いバージョンでの動作を保証するために、古い部分を捨てきることはできません。

今回から過去のJavaのバージョンをバッサリ切り捨て、Java8以降を標準としたモダンなWeb Frameworkのひとつとして Jooby を紹介していきます。

特徴

公式サイトには以下のように記載されています。

Jooby a scalable, fast and modular micro web framework for Java.

  • Scalable. Stateless application development.
  • Fast!. Thanks to the most popular NIO web servers.
  • Modular. Make it a full stack with modules
  • Simple, effective and easy to learn. Ideal for small but also large scale applications.
  • Ready for modern web, with the awesome and powerful asset module

まあ、この辺りはよくある売り文句なので素直に受け取らず、ふーん、くらいに思っておきます。 *2

たくさんのModuleを組み合わせてWeb Applicationを構築していくことができるようです。AWSのModuleもありますね。

QuickStart

ひとまずどのようなFrameworkなのかの雰囲気を掴んで見るために、まずは定番のQuick Startから確認してみます。

環境

Java8とMaven3が最低必須条件です。自分の環境は以下の通り。

  • Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
  • Apache Maven 3.3.9

Joobyのバージョンは以下で試しています。

  • 1.0.0.CR6

絶賛開発進行中のFrameworkのため、結構な速度でアップデートされているので、即情報が古くなる可能性がありますがご了承ください。

プロジェクト作成

プロジェクトを作成していきます。以下のコードを実行します。今回は以下の様なプロジェクトを作成してみます。

  • GroupID : jp.classmethod
  • Application Name : HelloJooby
  • Version : 1.0.0-SNAPSHOT
mvn archetype:generate -B -DgroupId=jp.classmethod -DartifactId=HelloJooby -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=jooby-archetype -DarchetypeGroupId=org.jooby -DarchetypeVersion=1.0.0.CR6

com.mycompanyjp.classmethod に変更し、Versionを 1.0.0 にしました。my-appHelloJooby に変更しています。

$ mvn archetype:generate -B -DgroupId=jp.classmethod -DartifactId=HelloJooby -Dversion=1.0.0-SNAPSHOT -DarchetypeArtifactId=jooby-archetype -DarchetypeGroupId=org.jooby -DarchetypeVersion=1.0.0.CR6
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] >>> maven-archetype-plugin:2.4:generate (default-cli) > generate-sources @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.4:generate (default-cli) < generate-sources @ standalone-pom <<<
[INFO]
[INFO] --- maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom ---
[INFO] Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.jar
(...snip...)
[INFO] Downloaded: https://repo.maven.apache.org/maven2/org/jooby/jooby-archetype/1.0.0.CR6/jooby-archetype-1.0.0.CR6.pom (2 KB at 3.0 KB/sec)
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: jooby-archetype:1.0.0.CR6
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: jp.classmethod
[INFO] Parameter: artifactId, Value: HelloJooby
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: package, Value: jp.classmethod
[INFO] Parameter: packageInPathFormat, Value: jp/classmethod
[INFO] Parameter: package, Value: jp.classmethod
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: jooby-version, Value: 1.0.0.CR6
[INFO] Parameter: groupId, Value: jp.classmethod
[INFO] Parameter: artifactId, Value: HelloJooby
[INFO] project created from Archetype in dir: /Users/komurohiraku/Develop/jooby/HelloJooby
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.420 s
[INFO] Finished at: 2016-07-06T15:23:34+09:00
[INFO] Final Memory: 16M/189M
[INFO] ------------------------------------------------------------------------

以下のような構成になっているかと思います。

  • HelloJooby
    • conf
    • pom.xml
    • public
    • src

IntelliJ IDEAにプロジェクトを読み込む

さすがにコンソール上で開発は厳しいので、普段使いのIntelliJ IDEAで編集、実行できるようにしておきます。作成されたプロジェクトをIntelliJ IDEAに取り込みます。Mavenプロジェクトなのでガイダンスに従ってプロジェクトのインポートを実行します。ぽちぽち

スクリーンショット 2016-07-06 15.25.11

Import Project をクリック。

スクリーンショット 2016-07-06 15.25.33

HelloJoobyディレクトリを選択してOKをクリック

スクリーンショット 2016-07-06 15.25.44

pom.xmlもあることですし、mavenを選択します。

最近gradleも対応したようです。

スクリーンショット 2016-07-06 15.25.56

読み込み元のRoot Directoryなどを設定します。基本的にはこのままで問題なさそう。

スクリーンショット 2016-07-06 15.26.08

先ほど maven コマンドで実行した通り、GroupId, VersionIdのままなので特に変更せずにこちらを選択。

スクリーンショット 2016-07-06 15.26.16

プロジェクト名とプロジェクトファイルの場所はそのまま。Finishをクリック。

スクリーンショット 2016-07-06 15.26.55

取り込み直後は、pom.xml ファイルだけで不安になりますが、一生懸命Dependenciesなどを引っ張ってきてるようなのでしばし待ち。上記のようなディレクトリ構成が現れればプロジェクトの取り込みが完了。

実行

早速実行してみましょう。作成したてのプロジェクトにはルートパスのGETのみレスポンスを返すコードが定義されています。

App.javaの実行をポチっと。

スクリーンショット 2016-07-06 15.41.39

しばし待ちます。

スクリーンショット 2016-07-06 15.42.30

http"//localhost:8080/ へブラウザからアクセスします。

スクリーンショット 2016-07-06 15.43.02

ブラウザ上でこのような表示になっていれば成功です。

アプリケーションコードを拝見

動作を確認できたので、次は細かくコードを確認していきます。

起動クラス

起動クラスを定義します。ここは所謂お決まりのパターンです。こちらを書いておけば、とりあえず起動されるという理解で良いのではないでしょうか(今は)

/**
 * @author jooby generator
 */
public class App extends Jooby {

  {
    get("/", () -> "Hello World!");
  }

  public static void main(final String[] args) throws Throwable {
    run(App::new, args);
  }
}

パスの定義も含めて、全て1ファイルに収まっているようです。Javaなので public static void main() の定義が確認できます。

run(App::new, args);

App::new はメソッド参照によるコンストラクタ呼び出しですので、古い記法に直すと以下のようになります。

run(new App(), args);

run の中身は以下のように定義されています。

public static void run(Supplier<? extends Jooby> app, String... args) throws Throwable {
    Config conf = ConfigFactory.systemProperties().withFallback(args(args));
    System.setProperty("logback.configurationFile", logback(conf));
    ((Jooby)app.get()).start(args);
}

logbackの表記が見えます。デフォルトで組み込まれてるようですね。

GET

GETメソッドの定義をしているブロックとラムダ式が気になります。こちらは何をしているのでしょう?

{
    get("/", () -> "Hello World!");
}

メソッドの処理そのものはとても簡単です。ルート/に対してGETメソッドでアクセスすると Hello World!という文字列を返却するだけです。

  • get() : GETメソッドに反応する処理を定義します。
  • "/" : パスを定義します。この場合は http://localhost:8080/ を示します。
  • () -> "Hello World!" : 引数なしのラムダ式がメソッド定義になります。上記パスに対してGETした際にこのメソッドが実行されます。

このブロックの中には、このような表記でメソッドとパス、それらに対する動作の定義をいくつも記述することができるようです。次回以降になりますが、モジュールの利用などもここで宣言するのが正しいようです。

まとめ

日本(というか世界でも)であまり情報がないFrameworkを某Javaな先生からオススメされて触り始めたのがJoobyです。ブログにするために勉強し始めています。色々と試行錯誤を繰り返しているところです。

SpringやStrutsなどのフレームワークとは一線を画する変態的なWeb Frameworkのようですが、まあ今までの知識も無駄にはならないでしょう。目新しい分新鮮で楽しいです。実際に実用レベルまでいけるのでしょうか?楽しみ半分、不安半分。

次回はアプリケーション全体のLifecycleを見てみます。

参照

脚注

  1. 一部既に終了が宣言されてますが。
  2. 経験上こういった言葉を額面通りに受け取ると、ちょっと視野狭窄になりかねないので危険。