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

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

1. 前書き

この記事では、run logic at the startup of a Spring applicationの方法に焦点を当てます。

参考文献:

Spring Boot Webアプリケーションを構成する

Spring Bootアプリケーションのより便利な設定のいくつか。

Spring Boot:メインクラスの構成

MavenとGradleでSpringBootアプリケーションのメインクラスを構成する方法を学びます。

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

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

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

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

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

@Component
public class InvalidInitExampleBean {

    @Autowired
    private Environment env;

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

ここでは、コンストラクターのautowiredフィールドにアクセスしようとしています。 コンストラクターが呼び出されるとき、Spring Beanはまだ完全に初期化されていません。 calling not yet initialized fields will of course result in NullPointerExceptionsであるため、これは問題があります。

Springはこの状況を管理するいくつかの方法を提供します。

2.1. @PostConstruct注釈

Javaxの@PostConstructアノテーションは、once immediately after the bean’s initializationを実行する必要があるメソッドにアノテーションを付けるために使用できます。 注入するものがない場合でも、注釈付きメソッドは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

このアプローチはrunning logic after the Spring context has been initializedに使用できるため、特定のBeanに焦点を当てるのではなく、すべてのBeanが初期化されるのを待ちます。

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

@Component
public class StartupApplicationListenerExample implements
  ApplicationListener {

    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();
}

そして、これはXML構成で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 BootCommandLineRunner

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

例を見てみましょう:

@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++;
    }
}

完全なソースコードはGithubにあります。

Notedocumentationで説明したように、複数のCommandLineRunner Beanを同じアプリケーションコンテキスト内で定義でき、@Orderedインターフェイスまたは@Orderアノテーションを使用して順序付けできます。 。

2.7. Spring BootApplicationRunner

CommandLineRunner,と同様に、Spring Bootは、アプリケーションの起動時に呼び出されるrun()メソッドを備えたApplicationRunnerインターフェースも提供します。 ただし、コールバックメソッドに渡される生のString引数の代わりに、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++;
    }
}

完全なソースコードはGithubにあります。

3. メカニズムの組み合わせ

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

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

  1. コンストラクタ

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

  3. InitializingBeanのafterPropertiesSet()メソッド

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

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

@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のアプリケーション起動時にロジックを実行する複数の方法を説明しました。

コードサンプルはGitHubにあります。