Jetty:組込Jettyを完全に組込する方法

2019年11月1日

jettyについての全投稿は/tag/jettyにあるので参照されたい

妙なタイトルだが、要するにこういうことだ。

あるアプリの中にJettyを組み込み、その上にウェブアプリをホスティングするのだが、ウェブアプリのJavaコードは、ホストとなったアプリケーションのコードやライブラリをそのまま利用する。つまり、ホスト側とウェブアプリ側の区別は必要無い。

通常、JettyやTomcat等のサーブレットコンテナでは、コンテナ側とその上に配備されるウェブアプリとは別個のものとして扱われるのだが、今回の場合にはそれらが一体不可分であり、分けて考える必要はない。単純に「ウェブサービス機能を持ったアプリ」でしかないのである。

これを簡単に行うにはどうしたら良いのか?

クラスローダにまつわる困難性

基本的にサーブレットコンテナ(Jettyを組み込んだアプリ側)と、その上で動作するウェブアプリの間で何らかのデータをやり取りするには一定の困難が生ずる。なぜなら、それらのクラスローダが異なるからである。

これを説明するのは非常に面倒なのだが、ともあれ、異なるクラスローダの間での相互呼び出しは非常に難しい。基本的に「異なるクラスローダであれば、無関係の異なるアプリ」と認識すべきである。

これをあえて、自由自在に相互の呼び出しが可能とするためには、クラスローダを同一にするほかはない。ホスト側のアプリと、ウェブアプリが同一のクラスローダで動作するようにする。

この方法は既にJetty:WebAppContext.setClassLoaderに記述した。

同一のクラスローダの意味

クラスローダが同一であるということは、本体アプリとウェブアプリのコードに区別がなくなるということだ。これにより、ウェブアプリのプログラムが、本体側にあっても良いことになる。どういうことかと言えば、通常ウェブアプリ、つまりwarファイルは以下のような構成になっている。

war
 + ユーザに公開されるファイル
 + WEB-INF
   + web.xml
   + ユーザに公開されないファイル
   + classes
   + lib

classes以下にウェブアプリ本体、lib以下に必要なライブラリが配備されるのだが、これらは必要無いということである。これらはすべて本体側に組み込めるので、

war
 + ユーザに公開されるファイル
 + WEB-INF
   + web.xml
   + ユーザに公開されないファイル

という状態で良い。

warファイルを展開しないで配備

Tomcatと同様にJettyでもwarファイルを与えるとデフォルトでその内容を展開してしまう(これは通常一時ファイル領域に行われる)のだが、これをさせずにwarファイルのまま扱わせることができる。このフラグとしてextractWARがある。

    WebAppContext warContext = new WebAppContext();
    warContext.setExtractWAR(false);

※lib下にjarファイルのある状態でこれを行うとエラーになる。jarファイルがwarファイル中に含まれた状態では実行できないようだ。

ただし、この場合でも一時ファイル領域は作成されてしまうようだ。

まとめ

ということで、あるJavaアプリ内に完全にJettyを組み込みにする方法としては以上である。

  • クラスローダを本体と同一にする
  • warファイル中には一切プログラムコードは不要
  • warファイルを展開させないようにする