[Java8][Framework] New Next Web Framework 「Jooby」入門 [Lifecycle]
はじめに
前回は手始めにHelloWorldでアプリケーションを起動してみました。今回から少しずつFrameworkの動作について確認していきます。今回は基本的な部分であるアプリケーションライフサイクル、アプリケーション設定、ログについて確認します。
前回と同じくJava8とMaven3が最低必須条件です。自分の環境は以下の通り。
- Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
- Apache Maven 3.3.9
Joobyのバージョンは以下で試しています。
- 1.0.0.CR7
もたもたしていたらCR7が出てしまいました。
Start, Stopイベント
アプリケーション及びモジュールはそれぞれ、 start
イベントと stop
イベントをhookして自前の処理を記述できるようです。 初期化処理 と 終了処理 などを記述するのが目的でしょうか。
{ onStart(() -> { log.info("starting app"); }); onStop(() -> { log.info("stopping app"); }); }
起動してみます。
[2016-08-04 14:59:37,873]-[main] INFO jp.classmethod.App - starting app [2016-08-04 14:59:38,213]-[main] INFO jp.classmethod.App - [dev@netty]: Server started in 1696ms listening on: http://localhost:8080/
停止してみます。
[2016-08-04 15:00:15,230]-[Thread-0] INFO jp.classmethod.App - stopping app [2016-08-04 15:00:15,231]-[Thread-0] INFO jp.classmethod.App - [netty] Server stopped Process finished with exit code 130
アプリケーションの起動時と終了時にlogが出力されているのが確認できます。全ソースは以下のとおりです。
/** * @author jooby generator */ public class App extends Jooby { Logger log = LoggerFactory.getLogger(App.class); { onStart(() -> { log.info("starting app"); }); onStop(() -> { log.info("stopping app"); }); } public static void main(final String[] args) throws Throwable { run(App::new, args); } }
インスタンスイニシャライザ
意識せずに使っていたのですが、Joobyのサンプルではインスタンスイニシャライザが多用されています。
public class Hoge() { private static Logger log = LoggerFactory.getFactory(Hoge.class); { // インスタンスイニシャライザでログ出力 log.info("initialize"); } /** * Constructor */ public Hoge() { // コンストラクタでログ出力 log.info("constructor"); } }
インスタンスイニシャライザはコンストラクタよりも先に実行される処理になります。上記コードを実行してみると initialize
→ constructor
の順でLogが出力されます。
コンストラクタ実行前に処理されるため、インスタンス変数の初期化などに利用されることが多いようです。
Joobyの場合、routingの設定から処理の記述をlambdaで行い、Function型の変数として初期化していることから、インスタンスイニシャライザを使っているようです。コンストラクタ内で大量に初期化するよりかはとても見やすいと思います。インスタンスイニシャライザはいくつも定義できるので、処理の異なるブロックなどに分けてあげることで見やすくなるかと思います。
Lifecycle
[App] Start, Stop時に処理を実行したい
アプリケーションの起動時、終了時のイベントに合わせて何らかの処理を実行したい場合は、onStart()
, onStop()
を使い、実行したい処理を実装します。
public class App extends Jooby { Logger log = LoggerFactory.getLogger(App.class); // Application起動、終了時設定 { onStart(() -> { // execute initialize log.info("starting app"); }); onStop(() -> { // execute before destruct log.info("stopping app"); }); } }
起動時には starting app
, 終了時には stopping app
というログが出力されます。
Start, Stopの処理をChainしたい
起動時や終了時に複数の処理をシーケンシャルに実行したい場合は、 onStart()
, onStop()
を多重定義すれば良いようです。宣言された順序に沿って実行されるので、定義する順序は適当ではいけません。
{ onStart(() -> { // execute initialize log.info("starting app"); }); onStart(() -> { // execute after print "starting app" log.info("and then Second"); }); onStart(() -> { // execute after print "and then Second" log.info("and then Third"); }); }
実行すると以下の様な結果が出力されます。
[2016-08-05 18:10:35,449]-[main] INFO jp.classmethod.App - starting app [2016-08-05 18:10:35,449]-[main] INFO jp.classmethod.App - and then Second [2016-08-05 18:10:35,450]-[main] INFO jp.classmethod.App - and then Third [2016-08-05 18:10:36,033]-[main] INFO jp.classmethod.App - [dev@netty]: Server started in 2738ms
starting app
, and then Second
, and then Third
とログが表示されているのが確認できます。
[Module] Start, Stop時に処理を実行したい
Joobyではアプリケーションクラスだけではなく、ModuleクラスもLifecycleに沿って、Start, Stopイベントが実行されます。こちらも同じようにイベントに合わせて処理を実装することが可能です。
public class MyModule implements Jooby.Module { private static Logger logger = LoggerFactory.getLogger(MyModule.class); @Override public void configure(Env env, Config config, Binder binder) { env.onStart(() -> { logger.info("Initialize MyModule"); }); env.onStop(() -> { logger.info("Destruct MyModule"); }); } }
JoobyのEnvは、アプリケーションのEnvironmentの値を管理するインタフェースです。起動引数などでEnvの値を指定し、切り替えたConfigオブジェクトに紐づく形で適宜切り替わるようです。
Lifecycleインタフェースを継承しているため、Joobyクラスと同様にModuleの起動と停止などのイベントで動作できるようです。
モジュールの読み込みはApp.javaのインスタンスイニシャライザの中で use()
を使い、インスタンスを生成します。
// import Module { use(new MyModule()); }
この状態で再度アプリケーションを実行してみます。
[2016-09-15 17:24:39,033]-[main] INFO jp.classmethod.modules.MyModule - Initialize MyModule [2016-09-15 17:24:39,034]-[main] INFO jp.classmethod.App - starting app [2016-09-15 17:24:39,823]-[main] INFO jp.classmethod.App - [dev@netty]: Server started in 2325ms
停止すると以下の様なログが出力されます。
[2016-09-15 17:25:37,715]-[Thread-1] INFO jp.classmethod.App - stopping app [2016-09-15 17:25:37,715]-[Thread-1] INFO jp.classmethod.modules.MyModule - Destruct MyModule [2016-09-15 17:25:37,718]-[Thread-1] INFO jp.classmethod.App - [netty] Server stopped
- モジュールの開始
- アプリケーションの開始
- アプリケーションの停止
- モジュールの停止
という順序で実行されるようです。
ログ
logbackが予め組み込まれていますので、特に何もせずにlogbackのクラスやメソッドは利用可能です。logbackに関して詳しいリンクはこちらへ
Logger log = LoggerFactory.getLogger(App.class);
設定ファイルは、conf/logback.xml
にデフォルトで配置されています。
EnvとConfについて
アプリケーション及びモジュールは、 application.env
の設定値に依存します。デフォルトでは dev
が設定されています。
stage
, prod
等を指定することで様々な設定値を変更することができます。アプリケーションの設定ファイル application.conf
の切り替えにも依存します。 application.prod.conf
等を作成しておくことでEnvによって切り替えることができます。
所謂SpringBootのProfile切り替えに概念としては近いのではないでしょうか。Envインタフェースのオブジェクトを参照することで、現在起動中のアプリケーションがどの環境を利用してるかを把握することができます。
env.onStart(() -> { logger.info("Initialize MyModule. env : {}", env.name()); });
上記で特に何もせずに起動すると、以下のLogが出力されます。
[2016-09-15 18:25:56,601]-[main] INFO jp.classmethod.modules.MyModule - Initialize MyModule. env : dev
Configインタフェースは、typesafeのライブラリです。Joobyのアプリケーション設定値は、こちらのインタフェースを通してアクセスします。 application.conf
の設定値を取得する場合は、Configインターフェースのオブジェクトを利用します。
まとめ
こうやって見てみると、今まで利用していたフレームワークのライブラリをいいとこ取りで構成されています。そのため、他のフレームワーク(SpringBootやPlay)を触っていると、「あ、このクラス見覚えあるわ」とか「あ、この記述見覚えあるわ」というものがあるため、意外とさくさく読めていきます。小さなモジュールを組み上げて作成していくことが出来るようなフレームワークのようなので、こういったパーツは他にもたくさん出てきそうです。