title: 【転載】SpringBoot の初期化時に何かをするための 6 つの方法!
date: 2021-08-24 15:19:00
comment: false
toc: true
category:
- Java
tags: - 転載
- Java
- SpringBoot
- 初期化
- 方法
- 方法
- コンテナ
- リフレッシュ
- リスナー
- 起動
- プロジェクト
- イベント
この記事は転載です:SpringBoot の初期化時に何かをするための 6 つの方法!
前書き#
実際の作業では、プロジェクトの起動時にスレッドプールの初期化や暗号証明書の事前読み込みなど、いくつかの初期化操作を行う必要があります。
さて、古典的な問題が出てきました。これは面接官がよく尋ねる質問でもあります:Spring Boot プロジェクトの起動時に何をする手段はありますか?
方法はいくつかありますが、以下に一般的な方法をいくつか紹介します。

1、コンテナリフレッシュ完了の拡張ポイント ApplicationListener<ContextRefreshedEvent>#
ApplicationContext のイベントメカニズムは、オブザーバーデザインパターンを実装したもので、ApplicationEvent と ApplicationListener の 2 つのインターフェースを通じて ApplicationContext のイベントメカニズムを実現しています。
Spring におけるいくつかの組み込みイベントは以下の通りです:
ContextRefreshedEvent:ApplicationContext が初期化またはリフレッシュされたときに、このイベントが発行されます。これは ConfigurableApplicationContext インターフェースの refresh () メソッドを使用しても発生します。ここでの初期化は、すべての Bean が正常にロードされ、後処理 Bean が検出されてアクティブ化され、すべての Singleton Bean が事前インスタンス化され、ApplicationContext コンテナが準備完了であることを指します。ContextStartedEvent:ConfigurableApplicationContext(ApplicationContext のサブインターフェース)インターフェースの start () メソッドを使用して ApplicationContext を起動するときに、このイベントが発行されます。データベースを調査したり、このイベントを受け取った後に停止したアプリケーションを再起動したりできます。ContextStoppedEvent:ConfigurableApplicationContext インターフェースの stop () を使用して ApplicationContext を停止するときに、このイベントが発行されます。このイベントを受け取った後に必要なクリーンアップ作業を行うことができます。ContextClosedEvent:ConfigurableApplicationContext インターフェースの close () メソッドを使用して ApplicationContext を閉じるときに、このイベントが発行されます。閉じられたコンテキストはライフサイクルの終わりに達し、リフレッシュまたは再起動することはできません。RequestHandledEvent:これは Web 特有のイベントで、すべての Bean に HTTP リクエストがサービスされたことを通知します。DispatcherServlet を使用する Web アプリケーションにのみ適用されます。Spring をフロントエンドの MVC コントローラーとして使用する場合、Spring がユーザーリクエストを処理した後に、このイベントが自動的にトリガーされます。
さて、上記の組み込みイベントを理解した後、Spring Boot の起動時にContextRefreshedEventをリスンしていくつかの操作を行うことができます。コードは以下の通りです:
@Component
public class TestApplicationListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println(contextRefreshedEvent);
System.out.println("TestApplicationListener............................");
}
}
高度な使い方#
特定のニーズを満たすためにカスタムイベントを作成することができます。たとえば、メール送信が成功した後にビジネス処理を行うことができます。
-
カスタム EmailEvent、コードは以下の通り:
public class EmailEvent extends ApplicationEvent{ private String address; private String text; public EmailEvent(Object source, String address, String text){ super(source); this.address = address; this.text = text; } public EmailEvent(Object source) { super(source); } //......addressとtextのsetter、getter } -
カスタムリスナー、コードは以下の通り:
public class EmailNotifier implements ApplicationListener{ public void onApplicationEvent(ApplicationEvent event) { if (event instanceof EmailEvent) { EmailEvent emailEvent = (EmailEvent)event; System.out.println("メールアドレス:" + emailEvent.getAddress()); System.out.println("メール内容:" + emailEvent.getText()); } else { System.out.println("コンテナ自体のイベント:" + event); } } } -
メール送信後にイベントをトリガーする、コードは以下の通り:
public class SpringTest { public static void main(String args[]){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //ApplicationEventオブジェクトを作成 EmailEvent event = new EmailEvent("hello","[email protected]","これはテストです"); //このイベントを手動でトリガー context.publishEvent(event); } }
2、SpringBootのCommandLineRunnerインターフェース#
コンテナの初期化が完了した後、CommandLineRunnerのrun()メソッドが呼び出され、コンテナ起動後に何かを完了させることができます。この方法は ApplicationListener と比較してより柔軟です。以下のように:
- 異なる
CommandLineRunnerの実装は、@Order()を使用して実行順序を指定できます。 - コンソールから入力されたパラメータを受け取ることができます。
以下にカスタム実装クラスを定義します。コードは以下の通り:
@Component
@Slf4j
public class CustomCommandLineRunner implements CommandLineRunner {
/**
* @param args コンソールから渡されたパラメータを受け取ります
*/
@Override
public void run(String... args) throws Exception {
log.debug("コンソールから受け取ったパラメータ>>>>"+ Arrays.asList(args));
}
}
この jar を実行するコマンドは以下の通り:
java -jar demo.jar aaa bbb ccc
上記のコマンドでは、aaa、bbb、cccの 3 つのパラメータが渡され、これらのパラメータはrun()メソッドで受け取られます。以下の図のように:

ソースコード分析#
私の文章を読んだファンは、CommandLineRunnerがどのように実行されるかを知っているはずです。原文:頭が薄くなるシリーズ、23 枚の図で Spring Boot の起動プロセスをソースコードから分析する~
Spring Boot がコンテキストをロードするエントリはorg.springframework.context.ConfigurableApplicationContext()メソッドにあります。以下の図のように:

CommandLineRunner はcallRunners(context, applicationArguments);メソッド内で実行され、ソースコードは以下の図のように:

3、SpringBootのApplicationRunnerインターフェース#
ApplicationRunnerとCommandLineRunnerは Spring Boot が提供するもので、CommandLineRunnerに比べてコンソールから渡されたパラメータのラッピングがより良好です。たとえば、--version=2.1.0のようにキーと値のペアで指定されたパラメータを取得できます。
この時、jar コマンドを実行するのは以下の通りです:
java -jar demo.jar --version=2.1.0 aaa bbb ccc
上記のコマンドでは、1 つのキーと値のペアversion=2.1.0と、3 つのパラメータaaa、bbb、cccが渡されます。
同様に、@Order()を使用して優先順位を指定できます。以下のコードのように:
@Component
@Slf4j
public class CustomApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.debug("コンソールから受け取ったパラメータ:{},{},{}",args.getOptionNames(),args.getNonOptionArgs(),args.getSourceArgs());
}
}
上記のコマンドを実行すると、結果は以下の図のようになります:

ソースコード分析#
CommandLineRunnerと同様に、callRunners()メソッド内で実行されます。ソースコードは以下の図のように:

4、@PostConstructアノテーション#
最初の 3 つはコンテナの初期化が完了した後に行うことに焦点を当てていますが、@PostConstructアノテーションは Bean の初期化が完了した後に行うことに焦点を当てています。たとえば、リスナーを登録するなどです。
@PostConstructアノテーションは一般的に Bean のメソッドに置かれ、Bean の初期化が完了した後にこのメソッドが呼び出されます。コードは以下の通り:
@Component
@Slf4j
public class SimpleExampleBean {
@PostConstruct
public void init(){
log.debug("Beanの初期化が完了し、呼び出し...........");
}
}
5、@Bean アノテーションで初期化メソッドを指定#
この方法は@PostConstructと似ており、Bean の初期化が完了した後に呼び出されるメソッドを指定します。
新しい Bean を作成するコードは以下の通り:
@Slf4j
public class SimpleExampleBean {
public void init(){
log.debug("Beanの初期化が完了し、呼び出し...........");
}
}
設定クラスで@Beanを使用してこの Bean をインスタンス化しますが、@Bean内のinitMethod属性で初期化後に実行するメソッドを指定する必要があります。以下のように:
@Bean(initMethod = "init")
public SimpleExampleBean simpleExampleBean(){
return new SimpleExampleBean();
}
6、 InitializingBeanインターフェース#
InitializingBeanの使い方は基本的に@PostConstructと同じですが、対応する Bean はafterPropertiesSetメソッドを実装する必要があります。コードは以下の通り:
@Slf4j
@Component
public class SimpleExampleBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
log.debug("Beanの初期化が完了し、呼び出し...........");
}
}
まとめ#
実現方法はいくつかありますが、著者は一般的な 6 つの方法をまとめただけです。学んだら、いいねを押してください。