LL言語並の速度でJavaウェブアプリケーションを開発する

結論

無理かもしれないけど

Spring Boot + Spring Loaded + Thymeleaf (+ Groovy シェル)

を使えば近づけることはできる。

※ 一番下にチュートリアル的なサンプルへのリンクがあります。

何が問題?

RubyPython、Node なんかを使った場合と違って、Java を使ったウェブアプリケーション開発はとにかく「待ち時間」が長くないですか?

API の実際の動作を確認したい」「画面表示を確認したい」と思ったら、アプリケーションサーバの種類にもよるけど結果を確認するのに数十秒から数分はかかる…… ゆっくり仕事していいよ というお告げを聞いているかのようですね。

そんなときに使いたいツールが「Spring Loaded (Spring 前提) 」と「Thymeleaf」。

Spring Loaded is 何

クラスファイルが変更されたら、アプリケーションサーバにリロードさせるエージェント。 いわゆる Hot code replace よりも広範囲な変更を反映できるし、反映の速度も速い、本当に速い。

使い方は簡単で、Spring Loaded の JAR をダウンロードして、Java プロセス起動時に次のように JVM オプションに指定してやるだけ。

% java -javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify SomeJavaClass

Maven で組み込み Tomcat を起動するような場合は MAVEN_OPTSJVM オプションを渡すことになる。

% MAVEN_OPTS="-javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify" mvn tomcat7:run

これで、クラスをコンパイルすれば再起動なしに即反映されるアプリケーションサーバ環境が手に入った。試しに Controller クラスの @RequestMappingvalue 値を書き換えてコンパイルすると、アノテーションの変更であっても即座反映されることが確認できる (ただし Interface の変更とかはダメっぽい) 。

ゆっくり仕事している暇 has lost...

Thymeleaf is 何

テンプレートエンジン。特徴は、テンプレートを、そのままウェブブラウザで表示可能な HTML として書けること。

HTML・CSS なんて、一発でうまいこと表示できるものが書けることのほうが稀で、試行錯誤を繰り返して作るもの 。そのサイクルが、本来であればブラウザをリロードする1秒で済むところ、Java のせいで60秒になってたとしたら、人月60倍、100万円のシステムが6000万円に化ける。おいしいwwwww

Thymeleaf はそんな目に合う機会を大幅に減らしてくれる。

使い方の例として、本のリスト books : List<Book> を、次のような表組みで出力する場合、

# Title Author Publisher
1 Java言語で学ぶデザインパターン入門 結城浩 ソフトバンクパブリッシング
2 Spring3入門 長谷川裕一 ほか 技術評論社

Thymeleaf では次のように書ける。

<table>
  <thead>
    <tr>
      <th>#</th>
      <th>Title</th>
      <th>Author</th>
      <th>Publisher</th>
    </tr>
  </thead>
  <tbody th:remove="all-but-first">
    <tr th:each="book, itr : ${books}">
      <td th:text="${itr.index} + 1">1</td>
      <td th:text="${book.title}">Java言語で学ぶデザインパターン入門</td>
      <td th:text="${book.author}">結城浩</td>
      <td th:text="${book.publisher}">ソフトバンクパブリッシング</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Spring3入門</td>
      <td>長谷川裕一 ほか</td>
      <td>技術評論社</td>
    </tr>
  </tbody>
</table>

th: プレフィックスで始まる属性が、Thymeleaf 用に使われるもの。th:each="book, itr : ${books}" によって、本の数だけ tr 要素と4つの td 子要素が繰り返し出力される。

注目すべき点は、レイアウトを作成するための画面モックに、いくつかの th: 属性を追加しただけであるということ。th: 属性はウェブブラウザでは解釈されない (invalid にはなるけど) のでレイアウトが崩れることはなく、画面モックとして役割も継続しつつテンプレートとしても動作する HTML が記述できる。さらに、th:remove="all-but-first" のような属性を使うと、「デプロイされたら最初の1つの子要素 (th:each が指定されている要素) だけ出力する」という制御が可能になる。

デザイナーとプログラマーの分業 has came true...

ついでに Spring Boot is 何

Java でウェブアプリケーションをつくろうと思ったとき、まずはじめにディレクトリのレイアウトを作って、依存モジュールを定義して、XML で設定を書いて……覚えてられないよ何があなたとJAVAだよ

そんなとき Spring Boot が便利なんですよ。

Spring Boot は、すぐに実行可能な Spring プロジェクトのひな形を作って、しかも依存モジュールの設定を自動的にしてくれる。例えば Thymeleaf がクラスパス上にあれば Thymeaf のテンプレート探索パス・キャッシュ有無・エンコーディングなどの設定が、HSQLDB がクラスパス上にあれば JDBC ドライバなどのデータソース設定が、自動的になされる*1

ひな形は次の方法で作ることができる。

2番目と3番目の方法は、内部的に1番目のジェネレータからひな形をダウンロードしてくるだけ。

ひな形が手に入ったら

% mvn spring-boot:run

で組み込み Tomcat が起動する。例によって Spring Loaded を有効にする場合は、こんな感じで起動するといい。

$MAVEN_OPTS="-javaagent:springloaded-1.2.1.RELEASE.jar -noverify" mvn spring-boot:run

http://localhost:8080 にアクセスしても、はじめは Controller を実装していないので404画面しかでない。Spring Loaded でメキメキ実装しけいけばいい。

チュートリアル的なサンプル

https://github.com/keik/spring-boot-tutorial

コミット順に上から並べています。

*1:内部的には、@Conditional というアノテーションを使って、クラスパス上にあるモジュールに応じて読み込まれる設定クラスを変える仕組みになっている