ninja frameworkとplayの比較

play2系を触ってみて1系から劣化したなーと思うところがninjaではどうなってるか見てみました。

環境毎の設定切り替え

play2系ではprefixによる設定の切り替えは廃止され、環境別の設定ファイルを用意する仕様になりました。
個人的には、小規模で使う分には1ファイルに全環境の設定を書いておきたいので、若干劣化したなぁ、という感覚でした。
ninjaはほぼほぼplay1系と同じ仕様で、起動時に渡す変数をprefixとして設定を切り替える形です。こちらの方が使いやすいかなー。

http://www.ninjaframework.org/documentation/configuration_and_modes.html

  • 起動時に ninja.mode を設定。
    mvn ninja:run -Dninja.mode=dev
    

  • application.conf

    database.name=database_production
    %dev.database.name=database_dev
    

自動実行ジョブ

play1系ではQuartzを使い、cronライクにシンプルに実装できましたが、
2系ではAkkaベースとなり設定の記述が複雑になってしまい、使いづらくなりました。
また、cronのように指定のタイミングで実行するのではなく、起動時から定期的に実行するだけの仕組みになりました。
ninjaではどうなったのか調べてみました。

http://www.ninjaframework.org/documentation/scheduler.html

  • Jobクラス
    @Singleton
    public class ScheduledAction {
        @Schedule(delay = 60, initialDelay = 5, timeUnit = TimeUnit.SECONDS)
        public void doStuffEach60Seconds() {
            // do stuff
        }
    }
    

  • Job登録

    public class Module extends AbstractModule {
        protected void configure() {
            bind(ScheduledAction.class);
        }
    }
    

んー、記述は簡単ですが、できることはplay2系と同じですね・・・
cronのような仕組みはあまり好まれないんですかね?

Session

http://www.ninjaframework.org/documentation/basic_concepts/sessions.html

playのSessionはJava ServletのHttpSessionとは全く異なる仕組みで実装されており、
サーバーには何も持たず、Cookieにすべてのコンテキストを保存します。
これはplayの思想であるshared nothingを実現するため、サーバー間でコンテキストを共有しないようにするためです。

ninjaもこの思想は引き継がれているようで、ninjaのSessionオブジェクトに値を設定すると、ブラウザのCookieに保存する仕様になっていました。
小規模ならLBでスティッキーにしてサーバーに全部保存したいんですが、やはりninjaでもサーバ側で保持したいコンテキスト情報は、Memcached等を併用する必要がありそうです。

マイクロフレームワークなしがし Spark編

マイクロフレームワークなにがしにて、ninja framework を触ってみましたが、
今度は Spark というフレームワークにトライしてみようと思います。

Webサイト

http://sparkjava.com/

セットアップ

https://sparktutorials.github.io/2015/04/02/setting-up-a-spark-project-with-maven.html

チュートリアルの通りにやると、POMを書いてmain関数にルーティング(+コントローラ)を記述するだけですね。
ninjaはplayライクなフレームワークでしたが、sparkはsinatraを模倣したフレームワークのようです。

import static spark.Spark.*;

public class Main {

	public static void main(String[] args) {
		get("/", (req, res) -> "hello world");
	}
}

main関数をjavaコマンドなどで通常のjavaアプリケーションとして実行します。
すると、Webサーバーが起動するので、ブラウザで http://localhost:4567 を開いて、hello worldが表示されればOK。

hello world

Viewのカスタマイズ

上記はレスポンスをそのまま返すだけなので、
今度はviewをテンプレート化します。

各種テンプレートエンジンの実装は、jarに分離されているので、下記を参考に、pomに依存関係を追加します。
http://sparkjava.com/documentation.html#views-templates

今回は、FreeMarkerを使った場合を試してみました。

  • Model
    public class Book {
    	private String name;
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    }
    

  • Controller

    public class Main {
    
    	public static void main(String[] args) {
    		Book book = new Book();
    		book.setName("日々創造");
    
    		get("/", (req, res) -> new ModelAndView(book, "book.ftl"), new FreeMarkerEngine());
    	}
    }
    

  • View (src/spark/template/freemarker/book.ftlに配置するのがポイント)

    book name: ${name}
    

  • 出力結果

    book name: 日々創造
    

テンプレートのディレクトリがデフォルトで spark/template/freemarker になっているので注意。
sinatraライクに書きたい方はsparkはオススメなのではないでしょうか。
個人的にはninjaの方が好みかも?

マイクロフレームワークなにがし Ninja編

最近Play frameworkに影響されたフレームワークがいくつか出ているようで、
マイクロフレームワークと呼ばれているようです。

Ninja Framework

今日ははその一つである Ninja framework を見ていきたいと思います。
とりあえず公式サイトに沿ってチュートリアルを動かしてみます。

http://www.ninjaframework.org/documentation/getting_started/create_your_first_application.html

mvn archetype:generate -DarchetypeGroupId=org.ninjaframework -DarchetypeArtifactId=ninja-servlet-archetype-simple
cd ninja-servlet-archetype-simple
mvn clean install
mvn ninja:run

これでとりあえず開発サーバが起動します。
Playのようにバイナリパッケージを展開してコマンドにPATHを通したりといった作業が必要ないところはいいかも。
ちなみに開発サーバのポートを変えたい場合は下記の通り。

mvn ninja:run -Dninja.port=8081

ブラウザで localhost:8081 を開くと初期状態のHomeが表示されます。
最初からwebjarsのbootstrapが組み込んであって好印象。

DBアクセス

続いてDBアクセスを試します。
これもチュートリアルに書いてあるとおり。
http://www.ninjaframework.org/documentation/working_with_relational_dbs/jpa.html

テーブルの作成はpersistence.xmlに下記の設定を追加し、JPA(Hibernate)に任せるのが基本的には楽ですが、

<property name="hibernate.hbm2ddl.auto" value="update"/>

自前でマイグレーションSQLを用意してテーブルを作成したい場合は、
Flyway というライブラリに則ってやる事も可能なようです。

  • conf/application.confに追記
    ninja.migration.run=true
    

  • db/migration/V1__hogehoge.sql
    create table Hoge (
      id int(11) primary key,
      name varchar(255)
    );
    

自動的にV1__hogehoge.sqlがDBに適用されます。テーブル名がおかしい場合など、自動的にFlywayがバリデートしてくれるようです。
個人的には開発中はHibernateの自動スキーマ作成に頼り、運用中は検証済みのDDLファイルを慎重に適用したい派なので、Flywayを使うことは無いかもしれません。
(Flywayのバリデートで謎のエラーが出て地味にハマったので・・・)

ちょっと触った感想

  • Controller,ViewがPlay1系に近い感じで好印象
  • DB周りは素のJPAなので、取っつきやすい反面、PlayのModel程は使いやすくなさそう
  • バイトコードをいじらないようなので、若干安心

しばらく触ってみたいと思います。