Spring BootのLazy InitializationをKotlinで試してみた

はじめに

Spring Boot 2.2.0からLazy Initializationが簡単に導入できるようになりました。Lazy Initializationを設定するとBeanを必要になるまで生成を遅らせます。メリットとしてはアプリケーションの起動速度の向上などの効果があります。サンプルを使って紹介したいと思います。

環境

  • Spring Boot 2.2.5
  • Kotlin 1.3.61

参考リンク

設定

次の設定を追加するだけで、BeanのLazy Initializationが有効になります。

spring:
  main:
    lazy-initialization: true

Lazy Initialization対象外にする方法

Lazy Initializationの対象外する方法として、次の方法があります。

  • @Lazy(false)のアノテーションを付加する
  • LazyInitializationExcludeFilterに対象外とするBeanの型を登録する

私は自分で定義するBeanに関しては@Lazy(false)を付加し、ライブラリが提供するBeanに関してはLazyInitializationExcludeFilterで対象外としています。

コード

今回のサンプルでメインに使用するクラスです。インスタンスを生成したタイミングで標準出力、printメソッドで標準出力します。

class DemoBean(private val beanName: String) {
    init {
        println("constructor:$beanName")
    }

    fun print() {
        println("method:$beanName")
    }
}

LazyInitializationExcludeFilterでLazy Initializationの対象外とするためのクラスです。先程のDemoBeanと実装内容は同じです。

class ExcludeDemoBean(private val beanName: String) {
    init {
        println("constructor:$beanName")
    }

    fun print() {
        println("method:$beanName")
    }
}

Beanを生成するクラスです。このクラスでは次のBeanを生成しています。

  • Lazy Initializationが有効となる「lazyDemoBean」
  • @Lazy(false)を付加した「notLazyDemoBean」
  • LazyInitializationExcludeFilterで指定された「excludeDemoBean」
  • Lazy Initialization対象外を指定する「lazyInitializationExcludeFilter」

※こちらのLazyIntializationExludeFilterのサンプルでは、Javaのコードになっており、staticメソッドでLazyInitializationExcludeFilterのBeanを生成していました。Kotlinでは、companion objectのメソッドとすることで動作しました。

import org.springframework.boot.LazyInitializationExcludeFilter
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Lazy

@Configuration
class DemoBeanFactory {

    @Bean("lazyDemoBean")
    fun lazyDemoBean(): DemoBean {
        return DemoBean("lazyDemoBean")
    }

    @Bean("notLazyDemoBean")
    @Lazy(false)
    fun notLazyDemoBean(): DemoBean {
        return DemoBean("notLazyDemoBean")
    }

    @Bean
    fun excludeDemoBean(): ExcludeDemoBean {
        return ExcludeDemoBean("excludeDemoBean")
    }

    companion object {
        @Bean
        fun lazyInitializationExcludeFilter(): LazyInitializationExcludeFilter {
            return LazyInitializationExcludeFilter.forBeanTypes(ExcludeDemoBean::class.java)
        }
    }
}

メインクラスの実装です。アプリケーションを開始したあとに、ApplicationContextから各Beanを取り出し、printメソッドを呼び出しています。

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication

@SpringBootApplication
class LazyInitializationDemoApplication

fun main(args: Array<String>) {

   println("ApplicationContextの初期化 開始")
   val ctx = runApplication<LazyInitializationDemoApplication>(*args)
   println("ApplicationContextの初期化 完了")

   val notLazyDemoBean = ctx.getBean("notLazyDemoBean",DemoBean::class.java)
   notLazyDemoBean.print()

   val excludeDemoBean = ctx.getBean("excludeDemoBean",ExcludeDemoBean::class.java)
   excludeDemoBean.print()

   val lazyDemoBean = ctx.getBean("lazyDemoBean",DemoBean::class.java)
   lazyDemoBean.print()
}

標準出力の結果は次のようになります。Lazy Initialization対象外にしたBeanはApplicationContextの初期化中にBeanが生成されているのがわかります。Lazy Initializationの対象となるlazyDemoBeanについてはApplicationContextから取得したタイミングでBeanが生成されているのがわかると思います。

ApplicationContextの初期化 開始
constructor:notLazyDemoBean
constructor:excludeDemoBean
ApplicationContextの初期化 完了
method:notLazyDemoBean
method:excludeDemoBean
constructor:lazyDemoBean
method:lazyDemoBean

 

終わりに

簡単にLazy Initializationの設定ができることがわかったと思います。開発環境やテスト実行時などに起動速度を上げたい場合に有効です。

参考リンクに言及がありますが、Lazy Initializationを有効にしていない場合、起動時にクラス定義が見つからないエラー、メモリ不足エラー、構成の誤りによるエラーなどが発生しますが、Lazy Initializationを有効にすることで発生を遅らせることがあります。本番環境では使用せずに、本番同等の環境でLazy Initializationを無効化したテストを実施することを考慮するべきだと思います。


--------------------------
システム開発のご要望・ご相談はこちらから

コメントを残す

メールアドレスが公開されることはありません。