春の起動時にセットアップデータを実行する

1前書き

この記事では、Springアプリケーションの起動時にロジックを実行する方法に焦点を当てます。

2起動時にロジックを実行する

Springアプリケーションの起動中または起動後にロジックを実行することは一般的なシナリオですが、複数の問題を引き起こすシナリオです。

Inverse of Controlの恩恵を受けるには、当然、アプリケーションのコンテナへの流れに対する部分的な制御を放棄する必要があります。そのため、インスタンス化、起動時のセットアップロジックなどに特別な注意が必要です。

ロジックをBeanのコンストラクタに含めることや、オブジェクトのインスタンス化後にメソッドを呼び出すことは簡単にできません。これらのプロセスの間、私たちは単に統制されていません。

実際の例を見てみましょう。

@Component
public class InvalidInitExampleBean {

    @Autowired
    private Environment env;

    public InvalidInitExampleBean() {
        env.getActiveProfiles();
    }
}

ここでは、コンストラクターの autowired フィールドにアクセスしようとしています。

コンストラクタが呼び出されたとき、Spring Beanはまだ完全に初期化されていません。まだ初期化されていないフィールドを呼び出すと、当然 __NullPointerException __sが発生するため、これは問題があります。

Springはこの状況を管理するいくつかの方法を私たちに与えています。

2.1. @ PostConstruct アノテーション

Javaxの @ PostConstruct アノテーションは、Beanの初期化直後に** 1回実行する必要があるメソッドにアノテーションを付けるために使用できます。

注入するものがなくても、注釈付きメソッドはSpringによって実行されることに注意してください。

これが @ PostConstruct の実際の動作です。

@Component
public class PostConstructExampleBean {

    private static final Logger LOG
      = Logger.getLogger(PostConstructExampleBean.class);

    @Autowired
    private Environment environment;

    @PostConstruct
    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

上記の例では、 Environment インスタンスが安全にインジェクトされ、 NullPointerException をスローせずに @ PostConstruct アノテーション付きメソッドで呼び出されたことがわかります。

2.2. InitializingBean インタフェース

InitializingBean アプローチは、前のものとほぼ同じように機能します。メソッドに注釈を付ける代わりに、 InitializingBean インタフェースと afterPropertiesSet() メソッドを実装する必要があります。

ここで、 InitializingBean インターフェースを使用して実装された前の例を見ることができます。

@Component
public class InitializingBeanExampleBean implements InitializingBean {

    private static final Logger LOG
      = Logger.getLogger(InitializingBeanExampleBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

2.3. ApplicationListener

このアプローチは、Springコンテキストが初期化された後にロジックを実行するために使用できます。したがって、特定のBeanに焦点を当てるのではなく、それらすべてが初期化されるのを待ちます。

これを実現するには、 ApplicationListener <ContextRefreshedEvent> インターフェースを実装するBeanを作成する必要があります。

@Component
public class StartupApplicationListenerExample implements
  ApplicationListener<ContextRefreshedEvent> {

    private static final Logger LOG
      = Logger.getLogger(StartupApplicationListenerExample.class);

    public static int counter;

    @Override public void onApplicationEvent(ContextRefreshedEvent event) {
        LOG.info("Increment counter");
        counter++;
    }
}

新しく導入された @​​ EventListener アノテーションを使用しても同じ結果が得られます。

@Component
public class EventListenerExampleBean {

    private static final Logger LOG
      = Logger.getLogger(EventListenerExampleBean.class);

    public static int counter;

    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {
        LOG.info("Increment counter");
        counter++;
    }
}

この例では__ContextRefreshedEventを選択しました。あなたのニーズに合った適切なイベントを選ぶようにしてください。

2.4. @ Bean initMethod 属性

__ initMethod __プロパティは、Beanの初期化後にメソッドを実行するために使用できます。

これがBeanの外観です。

public class InitMethodExampleBean {

    private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class);

    @Autowired
    private Environment environment;

    public void init() {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

特別なインターフェースが実装されていないことや特別な注釈が使用されていないことに気付くでしょう。

その後、 @ Bean アノテーションを使用してBeanを定義できます。

@Bean(initMethod="init")
public InitMethodExampleBean exBean() {
    return new InitMethodExampleBean();
}

そして、これはBean定義がXML設定でどのように見えるかです:

<bean id="initMethodExampleBean"
  class="org.baeldung.startup.InitMethodExampleBean"
  init-method="init">
</bean>

2.5. コンストラクタインジェクション

コンストラクタインジェクションを使用してフィールドをインジェクトする場合は、単にコンストラクタにロジックを含めることができます。

@Component
public class LogicInConstructorExampleBean {

    private static final Logger LOG
      = Logger.getLogger(LogicInConstructorExampleBean.class);

    private final Environment environment;

    @Autowired
    public LogicInConstructorExampleBean(Environment environment) {
        this.environment = environment;
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}

2.6. Spring Boot コマンドラインランナー

Springブートは、Springアプリケーションコンテキストがインスタンス化された後にアプリケーション起動時に呼び出すことができるコールバック run() メソッドを持つ CommanLineRunner インターフェースを提供します。

例を見てみましょう。

@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger LOG =
      LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    public static int counter;

    @Override
    public void run(String...args) throws Exception {
        LOG.info("Increment counter");
        counter++;
    }
}

完全なソースコードはhttps://github.com/eugenp/tutorials/blob/master/spring-boot[Github]にあります。

  • 注意** :https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html[documentation]で説明されているように、複数の CommandLineRunner Beanを同じ内に定義できますアプリケーションコンテキストであり、 @ Ordered インタフェースまたは @ Order アノテーションを使用して順序付けできます。

2.7. スプリングブート ApplicationRunner

CommandLineRunnerと同様に、 Spring bootはアプリケーションの起動時に呼び出される run() メソッドを持つ ApplicationRunner インターフェースも提供します。ただし、コールバックメソッドに渡される生の String 引数の代わりに、https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/ApplicationArguments.html[ ApplicationArguments のインスタンスがあります。]クラス。

ApplicationArguments インターフェースには、オプションである引数値と単純な引数値を取得するためのメソッドがあります。接頭辞 - - が付いている引数はオプション引数です。

例を見てみましょう。

@Component
public class AppStartupRunner implements ApplicationRunner {
    private static final Logger LOG =
      LoggerFactory.getLogger(AppStartupRunner.class);

    public static int counter;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        LOG.info("Application started with option names : {}",
          args.getOptionNames());
        LOG.info("Increment counter");
        counter++;
    }
}

完全なソースコードはhttps://github.com/eugenp/tutorials/blob/master/spring-boot[Github]にあります。

3組み合わせメカニズム

Beanを完全に制御するためには、上記のメカニズムを組み合わせて使用​​することをお勧めします。

実行順序は次のとおりです。

  1. コンストラクタ

  2. @ PostConstruct アノテーション付きメソッド

  3. InitializingBeanの afterPropertiesSet() メソッド

  4. XMLで init-method として指定されている初期化メソッド

すべてのメカニズムを組み合わせたSpring Beanを作成しましょう。

@Component
@Scope(value = "prototype")
public class AllStrategiesExampleBean implements InitializingBean {

    private static final Logger LOG
      = Logger.getLogger(AllStrategiesExampleBean.class);

    public AllStrategiesExampleBean() {
        LOG.info("Constructor");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info("InitializingBean");
    }

    @PostConstruct
    public void postConstruct() {
        LOG.info("PostConstruct");
    }

    public void init() {
        LOG.info("init-method");
    }
}

このBeanをインスタンス化しようとすると、上記で指定した順序と一致するログを見ることができます。

----[main]INFO o.b.startup.AllStrategiesExampleBean - Constructor[main]INFO o.b.startup.AllStrategiesExampleBean - PostConstruct[main]INFO o.b.startup.AllStrategiesExampleBean - InitializingBean[main]INFO o.b.startup.AllStrategiesExampleBean - init-method
----

4結論

この記事では、Springのアプリケーション起動時にロジックを実行する複数の方法を説明しました。

コードサンプルはhttps://github.com/eugenp/tutorials/tree/master/spring-all[GitHub]にあります。