SpringBoot 講義 9: SpringBoot 構成のホット デプロイメント開発ツール ツール
この記事は SpringBoot の 9 回目の講義です。SpringBoot の開発とデバッグでは、コード変更のすべての行を再起動してデバッグする必要がある場合、時間がかかることがあります。SpringBoot チームは、この問題に対して spring-boot-devtools (略して devtools) プラグインを提供しており、開発とデバッグの効率を向上させようとしています。
記事ディレクトリ
1. ナレッジポイントを準備する
1.1. ホットデプロイメントとホットローディングとは何ですか?
ホット デプロイメントとホット ロードは、アプリケーションの実行中にアプリケーションを自動的に更新 (クラスのリロードまたは置換など) する機能です。(spring-boot-devtools によって提供されるソリューションも再起動する必要がありますが、手動で再起動しなくても自動的にロードできます。)
厳密に言えば、ホット デプロイメントとホット ロードを区別する必要があります。Java プロジェクトの場合:
- ホットデプロイメント
- サーバーの実行中にプロジェクトを再デプロイします
- これはアプリケーション全体を直接リロードするため、メモリが解放され、ホット ロードよりもクリーンで完全な方法ですが、時間もかかります。
- ホットロード
- 実行時にクラスを再ロードすることにより、アプリケーションをアップグレードします。
- ホット ロードの実装原理は主にJVM の講義 2: クラス ロードのメカニズムに依存します。実装方法を要約すると、コンテナの起動時にバックグラウンド スレッドを開始し、クラス ファイルのタイムスタンプの変更を定期的に検出します。クラスのタイムスタンプが変更された場合、クラスは再ロードされます。
- リフレクションの仕組みと比較すると、リフレクションは実行時にクラス情報を取得し、動的呼び出しによってプログラムの動作を変更すること、ホットローディングは実行時にリロードしてクラス情報を変更し、プログラムの動作を直接変更することです。
1.2. LiveLoad とは何ですか?
LiveLoad は、ブラウザ クライアントの自動ロードと更新を提供するツールです。LiveLoad サーバーと LiveLoad ブラウザ プラグインの 2 つの部分に分かれています。devtools には LiveLoad サーバーが統合されているため、Web アプリケーションを開発し、ブラウザが自動的に更新されることが期待される場合は、現時点では LiveLoad を検討できます。
一度に実行できる LiveReload サーバーは 1 つだけです。アプリケーションを開始する前に、他の LiveReload サーバーが実行されていないことを確認してください。複数のアプリケーションが IDE から起動される場合、最初のアプリケーションのみが LiveReload をサポートします。
2. ホットデプロイメントを実装するために開発ツールを構成する
自動再起動モードでホットデプロイメントを実現するには、次の構成を使用します。
2.1、POM 構成
spring-boot-devtools 依存関係を追加
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!-- 可以防止将devtools依赖传递到其他模块中 好比 Java 中的 final 类,不能被其他类继承一样 -->
<optional>true</optional>
</dependency>
</dependencies>
2.2、IDEA配置
IDEA 開発ツールを使用する場合、通常は次の 2 つの方法があります。
-
方法 1:構成がない場合、手動で再起動アップデートをトリガーします (Command+F9)
(mvn compile
コンパイルを使用して再起動アップデートをトリガーすることもできます) -
方法 2: IDEA はランタイム コンパイルを有効にし、更新を自動的に再開する必要があります
セット 1 :
ファイル -> 設定 -> ビルド、実行、デプロイメント -> コンパイル
チェック: プロジェクトを自動的にビルドする
設定 2 :
IDEA は、[ファイル] -> [設定] -> [詳細設定] の最初の設定で設定できます。
2.3、application.yml 設定
spring:
devtools:
restart:
enabled: true #设置开启热部署
additional-paths: src/main/java #重启目录
exclude: WEB-INF/**
thymeleaf:
cache: false #使用Thymeleaf模板引擎,关闭缓存
2.4. LiveLoad の使用
spring-boot-devtools モジュールには、リソースが変更されたときにブラウザーの更新をトリガーするために使用できる組み込み LiveReload サーバーが含まれています。LiveReload ブラウザ拡張機能は Chrome、Firefox、Safari をサポートしており、livereload.com から無料でダウンロードできます。
または、Firefox などのブラウザー アドオン センターからダウンロードします。
インストール後は、次のアイコンで管理できます。
アプリケーションの実行中に LiveReload サーバーを起動したくない場合は、 spring.devtools.livereload.enabled プロパティを false に設定できます。
一度に実行できる LiveReload サーバーは 1 つだけです。アプリケーションを開始する前に、他の LiveReload サーバーが実行されていないことを確認してください。複数のアプリケーションが IDE から起動される場合、最初のアプリケーションのみが LiveReload をサポートします。
3. さらなる理解
devtool ツールを使用する開発者もいますが、深く理解できる人はほとんどいません。さらに理解を深めるために、次の質問を理解してください。
3.1. devtool の原理? 自動的に再起動するのはなぜですか?
アプリケーションも再起動するのはなぜですか。手動で再起動しないのに、ホット デプロイメントの再起動に spring-boot-devtools を使用することをお勧めします。
spring-boot-devtools は 2 つのクラス ローダー ClassLoader を使用します。1 つの ClassLoader は変更されないクラス (サードパーティの jar パッケージ) をロードし、もう 1 つの ClassLoader (ClassLoader の再起動) は変更されるクラス (カスタム クラス) をロードします。
ファイル監視スレッド (File Watcher) がバックグラウンドで起動され、監視対象ディレクトリ内のファイルが変更されると、元の再起動 ClassLoader が破棄され、新しい再起動 ClassLoader が再ロードされます。
ファイル変更後は、サードパーティの jar パッケージが再ロードされなくなり、カスタム クラスのみがロードされ、ロードされるクラスが少なくなるため、再起動が速くなります。
このため、アプリケーションを再起動する場合も同様です。手動で再起動しないのはなぜでしょうか。ホット デプロイメントの再起動には spring-boot-devtools を使用することをお勧めします。
自動再起動には次のような注意点があります。
- 自動再起動によりログが記録されます
(どのような状況で再起動するかをログに記録します)
によってオフにすることができます
spring:
devtools:
restart:
log-condition-evaluation-delta: false
- 自動的に再起動する必要のない一部のリソースを除外する
一部のリソースは、変更時に必ずしも再起動をトリガーする必要はありません。デフォルトでは、/META-INF/maven、/META-INF/resources、/resources、/static、/public、または /templates 内のリソースを変更しても再起動はトリガーされませんが、ライブ リロードはトリガーされます。これらの除外をカスタマイズする場合は、 spring.devtools.restart.exclude プロパティを使用できます。たとえば、/static、/public のみを除外するには、次のプロパティを設定します。
spring:
devtools:
restart:
exclude: "static/**,public/**"
これらのデフォルトを維持し、さらに除外を追加する場合は、spring.devtools.restart.additional-exclude
代わりにこのプロパティを使用します。
- カスタム再起動クラスローダー
再起動機能は、2 つのクラスローダーを使用して実装されます。ほとんどのアプリケーションでは、このアプローチはうまく機能します。ただし、クラスロードの問題が発生する場合があります。
デフォルトでは、IDE で開いているプロジェクトはすべて「restart」クラスローダーを使用してロードされ、通常の .jar ファイルはすべて「base」クラスローダーを使用してロードされます。マルチモジュール プロジェクトで作業していて、すべてのモジュールが IDE にインポートされているわけではない場合は、何かをカスタマイズする必要があるかもしれません。このために、ファイルを作成できますMETA-INF/spring-devtools.properties
。
spring-devtools.properties ファイルには、 restart.exclude および restart.include というプレフィックスが付いたプロパティを含めることができます。include 要素は「restart」クラスローダーにプルアップされる項目であり、exclude 要素は「Base」クラスローダーにプッシュダウンされる項目です。このプロパティの値は、次の例に示すように、クラスパスに適用される正規表現パターンです。
restart:
exclude:
companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
include:
projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
詳細については、こちらをご覧ください。
3.2. devtool は Jar にパッケージ化されますか?
原則として、devtool は開発とデバッグ中にのみ使用する必要がありますが、本番環境で jar パッケージを実行する場合は必要ありません。そのため、Spring は JAR にパッケージ化しますか?
- デフォルトでは、JAR にパッケージ化されません。
パッケージ化されたアプリケーションを実行すると、開発者ツールは自動的に無効になります。java -jar またはその他の特別なクラス ローダーを介して起動した場合、それは「実稼働環境アプリケーション」とみなされます。
- アプリケーションをリモートでデバッグする予定の場合
(運用環境では使用しないでください。信頼できるネットワーク上で実行している場合、または SSL で保護されている場合にのみ有効にしてください)
この場合、devtool はリモート デバッグも可能です。リモート クライアント アプリケーションは IDE 内から実行されるように設計されています。org.springframework.boot.devtools.RemoteSpringApplication
接続先のリモート プロジェクトと同じクラスパスを使用して実行する必要があります。アプリケーションに必要なパラメータは、接続先のリモート URL のみです。
たとえば、Eclipse または Spring Tools を使用していて、my-app という名前のプロジェクトが Cloud Foundry にデプロイされている場合は、次の手順を実行します。
- 「実行」メニューから「実行構成...」を選択します。
- 新しい Java アプリケーション「起動構成」を作成します。
- my-app プロジェクトを参照します。
org.springframework.boot.devtools.RemoteSpringApplication
メインクラスとして使用します。- https://myapp.cfapps.io をプログラム引数 (またはリモート URL など) に追加します。
実行中のリモート クライアントは次のリストのようになります。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: 2.5.4
2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
3.3. devtool がデフォルトでキャッシュ オプションを無効にするのはなぜですか?
Spring Boot でサポートされている一部のライブラリは、パフォーマンスを向上させるためにキャッシュを使用します。たとえば、テンプレート エンジンは、テンプレート ファイルを繰り返し解析することを避けるために、コンパイルされたテンプレートをキャッシュします。さらに、Spring MVC は静的リソースを提供するときに HTTP キャッシュ ヘッダーを応答に追加できます。
キャッシュは運用環境では非常に有益ですが、開発中は逆効果になる可能性があり、アプリケーションで加えた変更を確認できなくなります。このため、spring-boot-devtools はデフォルトでキャッシュ オプションを無効にします。
たとえば、Thymeleaf には、テンプレート エンジンのキャッシュを設定する spring.thymeleaf.cache が用意されています。spring-boot-devtools モジュールを使用する場合、spring-boot-devtools によってこれらのプロパティが自動的に設定されるため、これらのプロパティを手動で設定する必要はありません。
それでは、どのような構成が自動的に設定されるのでしょうか? DevToolsPropertyDefaultsPostProcessor
対応するデフォルト設定はクラス内にあります。
public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor {
static {
Map<String, Object> properties = new HashMap<>();
properties.put("spring.thymeleaf.cache", "false");
properties.put("spring.freemarker.cache", "false");
properties.put("spring.groovy.template.cache", "false");
properties.put("spring.mustache.cache", "false");
properties.put("server.servlet.session.persistent", "true");
properties.put("spring.h2.console.enabled", "true");
properties.put("spring.web.resources.cache.period", "0");
properties.put("spring.web.resources.chain.cache", "false");
properties.put("spring.template.provider.cache", "false");
properties.put("spring.mvc.log-resolved-exception", "true");
properties.put("server.error.include-binding-errors", "ALWAYS");
properties.put("server.error.include-message", "ALWAYS");
properties.put("server.error.include-stacktrace", "ALWAYS");
properties.put("server.servlet.jsp.init-parameters.development", "true");
properties.put("spring.reactor.debug", "true");
PROPERTIES = Collections.unmodifiableMap(properties);
}
もちろん、適用されたプロパティをデフォルトで spring-boot-devtools によって設定したくない場合は、application.yml で spring.devtools.add-properties を false に渡すことができます。
3.4. devtool はすべての Springboot アプリケーションに対してグローバル設定を行うことができますか?
グローバル devtools 設定は、 spring-boot-devtools.yml ファイルを $HOME/.config/spring-boot ディレクトリに追加することで構成できます。
これらのファイルに追加されたプロパティは、devtools を使用してマシン上のすべての Spring Boot アプリケーションに適用されます。たとえば、常にトリガー ファイルを使用するように再起動を構成するには、次のプロパティを spring-boot-devtools ファイルに追加します。
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
3.5. devtool を使用しない場合、他にどのようなオプションがありますか?
devtools を使用しない場合、どのような選択肢がありますか?
実際の開発プロセスでは、次の理由から devtool ツールは使用しません。
-
devtool 自体は再起動メソッドに基づいていますが、これはまだ実際のホット リプレース ソリューションではありません。JRebel は(有料です)
- JRebel はこの記事を参照できます:開発ツールの講義 27: Idea ホット ロード プラグイン JRebel のアクティブ化と使用
-
開発とデバッグで最も重要なことはトレードオフです
- 自動再起動のオーバーヘッドが手動再起動とそれほど変わらない場合は、手動で再起動することをお勧めします (オンデマンドで再起動)
- ほとんどの場合、メソッドの内部変更または静的リソースの変更であれば、IDEA の再構築 (Ctrl + Shift + F9) を通じてホット アップデートを実行できます。
-
また、変更したクラスファイルのホットデプロイを実現するツール Spring Loaded も用意されており、詳細はgithub アドレスの説明を参照してください。