1. 概要

このチュートリアルでは、プログラムでSpring Bootアプリケーションを再起動する方法を示します。

アプリケーションの再起動は、場合によっては非常に便利です。

  • 一部のパラメーターを変更したときに構成ファイルを再ロードする
  • 実行時に現在アクティブなプロファイルを変更する
  • 何らかの理由でアプリケーションコンテキストを再初期化する

この記事ではSpringBootアプリケーションを再起動する機能について説明しますが、SpringBootアプリケーションのシャットダウンに関する優れたチュートリアルもあることに注意してください。

それでは、Spring Bootアプリケーションの再起動を実装するさまざまな方法を見ていきましょう。

2. 新しいコンテキストを作成して再起動します

アプリケーションコンテキストを閉じて新しいコンテキストを最初から作成することで、アプリケーションを再起動できます。 このアプローチは非常に単純ですが、それを機能させるために注意しなければならない微妙な詳細がいくつかあります。

Spring Bootアプリのmainメソッドでこれを実装する方法を見てみましょう。

@SpringBootApplication
public class Application {

    private static ConfigurableApplicationContext context;

    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
    }

    public static void restart() {
        ApplicationArguments args = context.getBean(ApplicationArguments.class);

        Thread thread = new Thread(() -> {
            context.close();
            context = SpringApplication.run(Application.class, args.getSourceArgs());
        });

        thread.setDaemon(false);
        thread.start();
    }
}

上記の例でわかるように、別の非デーモンスレッドでコンテキストを再作成することが重要です。これにより、closeメソッドによってトリガーされるJVMのシャットダウンがアプリケーションを閉じるのを防ぎます。 そうしないと、JVMはデーモンスレッドが終了するのを待たずに終了するため、アプリケーションが停止します。

さらに、再起動をトリガーできるRESTエンドポイントを追加しましょう。

@RestController
public class RestartController {
    
    @PostMapping("/restart")
    public void restart() {
        Application.restart();
    } 
}

ここでは、restartメソッドを呼び出すマッピングメソッドを備えたコントローラーを追加しました。

次に、新しいエンドポイントを呼び出して、アプリケーションを再起動できます。

curl -X POST localhost:port/restart

もちろん、実際のアプリケーションにこのようなエンドポイントを追加する場合は、それも保護する必要があります。

3. アクチュエータの再起動エンドポイント

アプリケーションを再起動するもう1つの方法は、 SpringBootActuatorの組み込みのRestartEndpointを使用することです。

まず、必要なMaven依存関係を追加しましょう。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-cloud-starter</artifactId>
</dependency>

次に、application.propertiesファイルで組み込みの再起動エンドポイントを有効にする必要があります。

management.endpoint.restart.enabled=true

すべての設定が完了したので、 Reset Endpointをサービスに挿入できます。

@Service
public class RestartService {
    
    @Autowired
    private RestartEndpoint restartEndpoint;
    
    public void restartApp() {
        restartEndpoint.restart();
    }
}

上記のコードでは、 RestartEndpointbeanを使用してアプリケーションを再起動しています。 これは、すべての作業を実行する1つのメソッドを呼び出すだけでよいため、再起動するための優れた方法です。

ご覧のとおり、 ResetEndpoint を使用すると、アプリケーションを簡単に再起動できます。 一方、このアプローチには、前述のライブラリを追加する必要があるため、欠点があります。 まだ使用していない場合は、この機能だけではオーバーヘッドが大きすぎる可能性があります。 その場合、あと数行のコードしか必要としないため、前のセクションの手動によるアプローチに固執することができます。

4. アプリケーションコンテキストの更新

場合によっては、refreshメソッドを呼び出すことでアプリケーションコンテキストをリロードできます。

この方法は有望に聞こえるかもしれませんが、一部のアプリケーションコンテキストタイプのみが、すでに初期化されたコンテキストの更新をサポートしています。 たとえば、 FileSystemXmlApplicationContext GroovyWebApplicationContext、などがこれをサポートしています。

残念ながら、これをSpring Boot Webアプリケーションで試してみると、次のエラーが発生します。

java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts:
just call 'refresh' once

最後に、複数の更新をサポートするコンテキストタイプがいくつかありますが、これは避ける必要があります。 その理由は、 refresh メソッドは、アプリケーションコンテキストを初期化するためにフレームワークによって使用される内部メソッドとして設計されているためです。

5. 結論

この記事では、SpringBootアプリケーションをプログラムで再起動するさまざまな方法について説明しました。

いつものように、例のソースコードはGitHubにあります。