banner
biuaxia

biuaxia

"万物皆有裂痕,那是光进来的地方。"
github
bilibili
tg_channel

【転載】SpringBootの初期化時に何かをするための6つの方法!

title: 【転載】SpringBoot の初期化時に何かをするための 6 つの方法
date: 2021-08-24 15:19:00
comment: false
toc: true
category:

  • Java
    tags:
  • 転載
  • Java
  • SpringBoot
  • 初期化
  • 方法
  • 方法
  • コンテナ
  • リフレッシュ
  • リスナー
  • 起動
  • プロジェクト
  • イベント

この記事はSpringBoot の初期化時に何かをするための 6 つの方法から転載されています。


前書き#

実際の作業では、プロジェクトの起動時にスレッドプールの初期化や暗号証明書の事前読み込みなど、いくつかの初期化操作を行う必要があります。

そこで、クラシックな質問が出てきます。これは面接官がよく尋ねる質問でもあります:Spring Boot プロジェクトの起動時に何かをする手段は何ですか?

方法はいくつかありますが、以下に一般的な方法をいくつか紹介します。

image

1、コンテナリフレッシュ完了の拡張ポイント ApplicationListener<ContextRefreshedEvent>#

ApplicationContext のイベントメカニズムは、オブザーバーデザインパターンを実装しており、ApplicationEvent と ApplicationListener の 2 つのインターフェースを通じて ApplicationContext のイベントメカニズムを実現しています。

Spring にはいくつかの組み込みイベントがあります:

  1. ContextRefreshedEvent:ApplicationContext が初期化またはリフレッシュされたときに、このイベントが発行されます。これは ConfigurableApplicationContext インターフェースの refresh () メソッドを使用しても発生します。ここでの初期化は、すべての Bean が正常にロードされ、後処理 Bean が検出されてアクティブ化され、すべての Singleton Bean が事前インスタンス化され、ApplicationContext コンテナが準備完了であることを指します。
  2. ContextStartedEvent:ConfigurableApplicationContext(ApplicationContext のサブインターフェース)インターフェースの start () メソッドを使用して ApplicationContext を起動するときに、このイベントが発行されます。データベースを調査したり、このイベントを受け取った後に停止したアプリケーションを再起動したりできます。
  3. ContextStoppedEvent:ConfigurableApplicationContext インターフェースの stop () を使用して ApplicationContext を停止するときに、このイベントが発行されます。このイベントを受け取った後に必要なクリーンアップ作業を行うことができます。
  4. ContextClosedEvent:ConfigurableApplicationContext インターフェースの close () メソッドを使用して ApplicationContext を閉じるときに、このイベントが発行されます。閉じられたコンテキストはライフサイクルの終わりに達し、リフレッシュまたは再起動することはできません。
  5. 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............................");
    }
}

高度な使い方#

特定のニーズを満たすためにカスタムイベントを作成することもできます。例えば、メール送信が成功した後にビジネス処理を行うことができます。

  1. カスタム 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
    }
    
  2. カスタムリスナー、コードは以下の通り:

    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);
             }
         }
    }
    
  3. メール送信後、イベントをトリガーするコードは以下の通り:

    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、SpringBootCommandLineRunnerインターフェース#

コンテナの初期化が完了した後、CommandLineRunnerrun()メソッドが呼び出され、コンテナ起動後に何かを行うことができます。この方法は 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

上記のコマンドでは、3 つのパラメータaaabbbcccが渡され、これらのパラメータはrun()メソッドで受け取られます。以下の図のように:

image

ソースコード分析#

私の文章を読んだファンは、CommandLineRunnerがどのように実行されるかを知っているはずです。元の文:頭が薄くなるシリーズ、23 枚の図で Spring Boot の起動プロセスをソースコードから分析する~

Spring Boot がコンテキストをロードするエントリはorg.springframework.context.ConfigurableApplicationContext()メソッドにあります。以下の図のように:

image

CommandLineRunner を呼び出すのはcallRunners(context, applicationArguments);というメソッドで実行されます。ソースコードは以下の図のように:

image

3、SpringBootApplicationRunnerインターフェース#

ApplicationRunnerCommandLineRunnerはどちらも Spring Boot が提供するもので、CommandLineRunnerに比べてコンソールから渡されたパラメータのラッピングがより良好です。例えば、--version=2.1.0のようにキーと値のペアで指定されたパラメータを取得できます。

この時、jar を実行するコマンドは以下の通り:

java -jar demo.jar --version=2.1.0 aaa bbb ccc

上記のコマンドでは、4 つのパラメータが渡されます。1 つのキーと値のペアversion=2.1.0と、他の 3 つはそれぞれaaabbbcccです。

同様に、@Order()を使用して優先順位を指定できます。以下のコードのように:

@Component
@Slf4j
public class CustomApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("コンソールから受け取ったパラメータ:{},{},{}",args.getOptionNames(),args.getNonOptionArgs(),args.getSourceArgs());
    }
}

上記のコマンドを実行すると、結果は以下の図のようになります:

image

ソースコード分析#

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

image

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 をインスタンス化しますが、@BeaninitMethod属性で初期化後に実行するメソッドを指定する必要があります。以下のように:

@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 つの方法をまとめただけです。学んだ方はいいねを押してください。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。