普通の Spring Boot 2.0 Web Applicatrion 〜 Spring Boot DevTools で Automatic Restart 〜


Spring Boot 2 で、なるべく標準的なやり方で、トラディショナルな Spring MVC による Web Application を作成するチュートリアルを数回に分けて。

の5回目です。

目次

今回は 「Spring Boot DevTools で Automatic Restart」の回となります。


Spring Boot DevTools

spring-boot-devtools を使うと Automatic Restart と LiveReload が実現できます。

Automatic Restart はクラスの変更を検知してアプリケーションの再起動を自動的行うものです。

LiveReload はファイルの変更を自動で検知してブラウザのリロードを自動でおこなうものです。

いずれも開発時の時間短縮に効果を発揮します。


spring-boot-devtools の導入

導入は build.gradle に以下の依存を追加するだけです。

dependencies {
    // ・・・
    compile 'org.springframework.boot:spring-boot-devtools'
}


Automatic Restart はクラスパス上のファイル変更を検知して自動的にアプリケーションを再起動させることができます。


Automatic Restart は2つのクラスローダを使ってい実現されており、再読込が不要なサードパーティーJar などを読み込むベースクラスローダと、開発しているアプリケーションを読み込むリスタートクラスローダがそれです。アプリケーションの再起動は、ベースクラスローダはそのままに、リスタートクラスローダを破棄して再作成することで実現されます(Spring-Loaded は javaagent を利用してバイトコードを動的に書き換えることで変更を反映しておりアプローチが違う)。


LiveReload はフロントエンド開発でよくあるのと同じで、ファイルの変更を検知してブラウザのリロードを自動的に行うものです。

組み込みの LiveReload サーバが起動し、ブラウザのエクステンションと通信することでページのリロードが自動で行われます。


Automatic Restart の実行

といっても、普通に bootRun すれば使えます。

IDE に依存しないやり方はターミナルを2つ使います。

  • 一つのターミナルで ./gradlew bootRun でアプリケーションを起動する
  • もう一つのターミナルで ./gradlew classes で変更内容をコンパイルする

Gradle の classescompileJavaprocessResources に依存するのでクラスファイルとリソースファイルが変更され、この変更が自動で検知され、アプリケーションの再起動が自動的に行われるようになります。


Automatic Restart の設定

Thymeleaf はデフォルトでテンプレートのコンパイル結果をキャッシュします。

これを変更するには application.properties または application.yml でキャッシュ設定を Off にする必要があります。

これは例えば、src/main/resources/config/application.yml に以下のように設定します(環境別の設定切り替えは連載の後半で説明します)。

spring.thymeleaf.cache: false


しかし、 spring-boot-devtools モジュールは、これらのプロパティを開発時設定に自動的適用します。なので、 processResources でリソースがコピーされただけでテンプレートの変更点が反映されるようになります。

これは Groovy テンプレートの spring.groovy.template.cache であったりVelocityテンプレートの spring.velocity.cache であったりも同様です。


spring-boot-devtools はデフォルトで次のリソースは再起動のトリガ対象から除外されています。

/META-INF/maven, /META-INF/resources, /resources, /static, /public, /templates

つまり、Thymeleaf のテンプレートを変更し、./gradlew processResources しても再起動は行われません。が、前述のキャッシュがoffとなっているため変更内容は反映されます。

この除外対象を変更するには、application.properties または application.ymlspring.devtools.restart.exclude(デフォルトの上書き) や spring.devtools.restart.additional-exclude(デフォルトへの追加) を設定します。


その他は以下のような設定があります。

spring:
  devtools:
    restart:
      enabled: true                                # 再起動の有効/無効
      exclude: "static/**, public/**"            # 除外パターン
      additional-exclude: "**/*.xml"             # 追加の除外パターン
      additional-paths: ['src/main/resources/sql'] # 監視パスを配列で指定
      trigger-file: .reload                         # 再起動のトリガファイルを指定


IntelliJ IDEA で Automatic Restart

bootRun ではなく、IDEA からmainメソッドを実行した場合、リスタートの監視対象は out/production/classes/ となります(bootRun の場合は build/classes/java/main/ build/resources/main/ )。


これは起動時のログを見るとわかります。

org.springframework.boot.devtools.restart.ChangeableUrls - Matching URLs for reloading : [file:/・・・/spring-boot-stdweb/out/production/classes/]


IDEA のデフォルト設定では、ソース編集内容は自動的に保存されます。そしてそのタイミングでビルドは行われません。よって、main メソッドから起動時には 「Build」-「Build Project」を行ったタイミングでリスタートが行われます。

なので、Eclipse のようにファイル保存を ⌘ F9 (Build Project) と読み替えると良いです。


どうしてもファイル保存時にリスタートしたいという場合は、

  • Preferences… - build,execution,deployment - compiler - build project automatically にチェック
  • Ctrl+SHIFT+A -> Registry - compiler.automake.allow.when.app.running にチェック

とすることで自動ビルドが有効になりますが、先に述べたように編集内容は自動的に保存されてしまい、意図しないタイミングでリスタートが走るためあまりオススメできません。普通に Build Project (⌘ F9) した方がよいです。


やるのであれば、File - Save AllBuild - Build Project をマクロ登録してお好みのキーバインドに割り当てる方が良いですね。


IntelliJ IDEA と Gradle プロジェクト

IDEA で Gradle プロジェクトを開くには、File - New - Project from Existing Sources…から build.gradle を開いてやればよいです。

この場合、Build Project (⌘ F9) した結果は ./out ディレクトリ以下にコンパイル結果が保存されます。


これを Gradle と同じ出力先 build 以下に変えるには idea プラグインを使います。

plugins {
    id 'java'
    id 'idea'
    id 'org.springframework.boot' version '2.0.1.RELEASE'
}
・・・

idea{
    module{
        inheritOutputDirs = false
        outputDir = compileJava.destinationDir
        testOutputDir = compileTestJava.destinationDir
    }
}

idea プラグインを入れた後、以下のようにすれば、

$ ./gradlew idea

...
Generated IDEA project at file:///・・・/spring-boot-stdweb/spring-boot-stdweb.ipr


ipr ファイルが作成されます。

この ipr ファイル からIDEA でプロジェクトを開くとビルドの出力先が build 以下になり、main メソッドから実行した場合も、bootRun した場合と同様に build/classes/java/main/ build/resources/main/ になります。

こうすることで、ターミナルからbootRun して、IDEA からビルドした結果でアプリケーションのリスタートを行うことができるようになります。


個人的には idea プラグインは入れず、ターミナルで bootRun しつつ、IDEA から Gradle の classes タスクを実行するやり方の方がいいと思います。

LiveReload

LiveReload を行うには spring-boot-devtools の導入の他にブラウザにアドオンを入れる必要があります。

Firefox Add-ons

https://addons.mozilla.org/ja/firefox/addon/livereload-web-extension/

Chrome ウェブストア

https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=ja

アドオンを入れると、以下のように LiveReload ボタンが現れるので、ボタンを押して有効化すれば準備完了です(緑色のアイコンです)。

f:id:Naotsugu:20180604233254p:plain

テンプレート変更して

$ ./gradlew processResources

とすれば自動的にブラウザのリロードが行われるようになります。

簡単ですね。



今回はここまでで、次回に続きます。