Spring Boot + Spring Data Redis/KeyValueプロジェクトがあります。すべての依存関係が埋め込まれた状態でアプリケーションを実行するようにSpringプロファイルをセットアップしました。そこで、起動時に組み込みRedisサーバーを起動します。 Spring Bootアプリケーションを停止したときにRedisサーバーを停止したい場合を除いて、Eclipseで起動するとすべてが正常に機能します。そのため、いくつかのシャットダウンフックを設定しましたが、Eclipseからアプリケーションを終了するときに呼び出されません。
それらはSOに関する同様の質問ですRedisソリューションがあることを期待してこれを作成しました。また、これらの同様の質問は、Spring Bootに固有のものではありません。
私は多くのことを試しました:
ExitCodeGenerator
;DisposableBean
;@PreDestroy
;それらのどれも呼び出されません。
おそらく、Redisオプション、タイムアウト、キープアライブなどがあります。ボックスの外にある何か気づいていませんか? Spring Bootアプリが突然停止したときに、Redisサーバーが停止していることをどのように確認できますか?
=>私はこれを見た 春のブーツ用の埋め込みRedis だが@PreDestroy
は、アプリケーションを突然終了したときに呼び出されません。
同様の質問のいくつかを次に示します。
また、Eclipse.orgでこの投稿を見て、Eclipseからアプリケーションを停止するときにシャットダウンフックが呼び出されない方法について説明しました: Graceful shutdown of Java Applications
ここに私のすべての関連コードがあります:
起動するコンポーネント組み込み起動時のRedisサーバー(停止しようとしても!!):
@Component
public class EmbeddedRedis implements ExitCodeGenerator, DisposableBean{
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.stop();
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
@Override
public int getExitCode() {
redisServer.stop();
return 0;
}
@Override
public void destroy() throws Exception {
redisServer.stop();
}
}
application.properties:
spring.redis.port=6379
Spring Boot App:
@SpringBootApplication
@EnableRedisRepositories
public class Launcher {
public static void main(String[] args){
new SpringApplicationBuilder() //
.sources(Launcher.class)//
.run(args);
}
@Bean
public RedisTemplate<String, Model> redisTemplate() {
RedisTemplate<String, Model> redisTemplate = new RedisTemplate<String, Model>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName("localhost");
return jedisConnectionFactory;
}
}
Redisサーバー(〜埋め込み)実行中:
$ ps -aef | grep redis
... /var/folders/qg/../T/1472402658070-0/redis-server-2.8.19.app *:6379
埋め込まれたRedis maven依存関係:
<dependency>
<groupId>com.github.kstyrc</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.6</version>
</dependency>
SpringBootとEclipseを使用する場合、 [〜#〜] sts [〜#〜] (Spring Tool Suite)Eclipseプラグインをインストールして、正常なシャットダウンを実現できます。
インストールしたら、通常の「Javaアプリケーション」ではなく「Spring Boot App」としてアプリケーションを実行します(実行/デバッグ構成)
「ライフサイクル管理を有効にする」チェックボックスがオンになっていることを確認します。赤い四角ボタンをクリックしてアプリケーションを停止すると、強制終了の代わりに正常なシャットダウンが実行されます。
編集:
「赤い四角ボタン」が2つあることに注意してください。 1つは[起動]ツールバーにあり、もう1つは[コンソール]パネルにあります。起動ツールバーの1つはハードキルを実行しますが、コンソールの1つはスプリングブートアプリケーションの正常なシャットダウンを可能にします(STSで起動)
調査の結果、Eclipse
はアプリケーションを終了するだけで、シャットダウンフックが実行される機会がないことがわかりました。
_Spring-Boot
_の配線方法のおかげで、回避策/ハックを見つけました。 mainメソッドが実行されると、Tomcatは別のスレッドで開始され、mainメソッドは完了するまで実行を続けます。これにより、Enterキーを押したときに終了ロジックを挿入できました。
アプリケーションは正常に起動し、コンソールはEnterキーがSystem.exit(1);
を実行するのを待つだけです。
_@SpringBootApplication
@EnableRedisRepositories
public class Launcher {
public static void main(String[] args){
new SpringApplicationBuilder() //
.sources(Launcher.class)//
.run(args);
System.out.println("Press 'Enter' to terminate");
new Scanner(System.in).nextLine();
System.out.println("Exiting");
System.exit(1);
}
}
_
Eclipseからアプリケーションを起動するとき、インターフェースからアプリケーションを終了する代わりに、コンソールでEnterキーを押します。これで、シャットダウンフック(_@PreDestroy
_)がトリガーされ、Redisサーバーが停止します。
私が望んでいたことではありませんが、少なくとも当面は、Embedded Redis Serverがアプリケーションで停止され、手動で強制終了する必要はありません。
ExitCodeGenerator
は、アプリケーションがexit
メソッドを呼び出す必要があります
System.exit(SpringApplication
.exit(SpringApplication.run(SampleBatchApplication.class, args)));
さらに シャットダウンフック を登録できます。フックが呼び出されます
System.exit
)。Ctrl+C
、SIGINT
)またはシグナル(SIGHUP
、SIGTERM
)。状況によっては、VMが正常にシャットダウンしない場合(SIGKILL
、internal VMエラー、ネイティブメソッドのエラー))、シャットダウンフックが呼び出されるかどうかを保証します。
EmbeddedRedis
コンポーネントのコードは次のようになります。
@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.start();
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
redisServer.stop();
}
});
}
Redisではなく、同じ問題がありました。他の開発者が望まない場合にSTSを追加する必要がないように、私は最大限の移植性を望みました。これを任意のSpring Bootアプリケーションに追加して、クリーンシャットダウンを提供できます。 OP自身の答えを詳しく説明したのは、ここにあります。
これをメインクラスまたは@Configuration
クラスに追加します。
@Bean
public ApplicationRunner systemExitListener() {
return args -> {
if (args.getOptionValues("exitListener") != null) {
System.out.println("Press Enter to exit application");
new Scanner(System.in).nextLine();
System.out.println("Exiting");
System.exit(0);
}
};
}
次に、Eclipse(または、選択したIDE =選択、またはコマンドラインで)で、引数--exitListener
を追加してコードをアクティブにします。Eclipseでは、実行構成にあります、「引数」タブの「プログラムの引数」ボックス。