[JAVA] I tried Lazy Initialization with Spring Boot 2.2.0

Spring Boot v2.2.0

Spring Boot v2.2.0 has been released and is now GA.

So, let's examine one of its functions, Lazy Initialization.

Spring Boot 2.2.0 Release v2.2.0.RELEASE · spring-projects/spring-boot · GitHub Spring Boot 2.2 Release Notes · spring-projects/spring-boot Wiki · GitHub Spring Boot Reference Documentation

environment

Creating a Project

The Hinagata Project is created from Spring Initializr.

spring-initializr.PNG

Gradle I have confirmed that Gradle 5.6.2 is applied to the Gradle project created by Spring Initializr.

> gradlew -version

------------------------------------------------------------
Gradle 5.6.2
------------------------------------------------------------

Build time:   2019-09-05 16:13:54 UTC
Revision:     55a5e53d855db8fc7b0e494412fc624051a8e781

Kotlin:       1.3.41
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM:          13-ea (Oracle Corporation 13-ea+33)
OS:           Windows 10 10.0 amd64

Lazy Initialization

Lazy Initialization is to generate the bean managed by ApplicationContext when the target bean is called, not when the application is started (≒ ApplicationContext is initialized).

This mechanism has been available from previous versions, but from v2.2.0, Lazy Initialization will be applied uniformly by applying true to propertyspring.main.lazy-initialization.

spring:
  main:
    lazy-initialization: true
package jp.co.musako.domain.model;

public class LazyInitializationDemoBean {

    private String message;

    public LazyInitializationDemoBean(String message) {
        this.message = message;
        System.out.println("call constructor " + this.message);
    }

    public void writer(String message){
        System.out.println(this.message + " is " + message);
    }
}
package jp.co.musako.config;

import jp.co.musako.domain.model.LazyInitializationDemoBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    @Bean("lazyInitializationDemoBean1")
    public LazyInitializationDemoBean lazyInitializationDemoBean1(){
        return new LazyInitializationDemoBean("create lazyInitializationDemoBean1");
    }

    @Bean("lazyInitializationDemoBean2")
    public LazyInitializationDemoBean lazyInitializationDemoBean2(){
        return new LazyInitializationDemoBean("create lazyInitializationDemoBean2");
    }
}
package jp.co.musako;

import jp.co.musako.domain.model.LazyInitializationDemoBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
        System.out.println("Initialize Application Context");

        LazyInitializationDemoBean bean1 = ctx.getBean("lazyInitializationDemoBean1", LazyInitializationDemoBean.class);
        bean1.writer("first bean");

        LazyInitializationDemoBean bean2 = ctx.getBean("lazyInitializationDemoBean2", LazyInitializationDemoBean.class);
        bean2.writer("second bean");
    }
}

Execution result

>gradlew bootRun

> Task :bootRun

2019-10-23 18:16:37.620  INFO 12708 --- [           main] jp.co.musako.Application                 : Started Application in 4.295 seconds (JVM running for 4.933)
Initialize Application Context
call constructor lazyInitializationDemoBean1
lazyInitializationDemoBean1 is first bean
call constructor lazyInitializationDemoBean2
lazyInitializationDemoBean2 is second bean

Here, you can see that the processing is done in the following order.

  1. Start application --Output "Initialize Application Context" after startup
  2. Bean generation --Output "call constructor lazyInitializationDemoBean1" in the bean constructor
  3. The writer method of the generated bean is called --Output "lazyInitializationDemoBean1 is first bean" with writer method

Exemption from Lazy Initialization

There are the following ways to exclude a specific bean from LazyInitialization while applying LazyInitialization to the project by setting spring.main.lazy-initialization = true.

  1. Set @ org.springframework.context.annotation.Lazy (false) to Bean
  2. Register the bean to be excluded in ʻorg.springframework.boot.LazyInitializationExcludeFilter`
package jp.co.musako.config;

import jp.co.musako.domain.model.ExcludeLazyInitializationDemoBean;
import jp.co.musako.domain.model.LazyInitializationDemoBean;
import org.springframework.boot.LazyInitializationExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class Config {
    
    @Bean
    static LazyInitializationExcludeFilter integrationLazyInitExcludeFilter() {
        return LazyInitializationExcludeFilter.forBeanTypes(ExcludeLazyInitializationDemoBean.class);
    }

    //Lazy Initialization applicable
    @Bean("lazyInitializationDemoBean1")
    public LazyInitializationDemoBean lazyInitializationDemoBean1(){
        return new LazyInitializationDemoBean("lazyInitializationDemoBean1");
    }

    //Not applicable to Lazy Initialization
    @Bean("lazyInitializationDemoBean2")
    @Lazy(false)
    public LazyInitializationDemoBean lazyInitializationDemoBean2(){
        return new LazyInitializationDemoBean("lazyInitializationDemoBean2");
    }

    //Not applicable to Lazy Initialization
    @Bean
    public ExcludeLazyInitializationDemoBean ExcludeLazyInitializationDemoBean(){
        return new ExcludeLazyInitializationDemoBean("excludeLazyInitializationDemoBean");
    }
}
package jp.co.musako;

import jp.co.musako.domain.model.ExcludeLazyInitializationDemoBean;
import jp.co.musako.domain.model.LazyInitializationDemoBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
        System.out.println("Initialize Application Context");

        LazyInitializationDemoBean bean1 = ctx.getBean("lazyInitializationDemoBean1", LazyInitializationDemoBean.class);
        bean1.writer("first bean");

        LazyInitializationDemoBean bean2 = ctx.getBean("lazyInitializationDemoBean2", LazyInitializationDemoBean.class);
        bean2.writer("second bean");

        ExcludeLazyInitializationDemoBean ExcludeLazyInitializationBean = ctx.getBean("ExcludeLazyInitializationDemoBean", ExcludeLazyInitializationDemoBean.class);
        ExcludeLazyInitializationBean.writer("third bean");
    }

}

>gradlew bootRun

> Task :bootRun

call constructor lazyInitializationDemoBean2
call constructor excludeLazyInitializationDemoBean
2019-10-23 18:52:52.464  INFO 6004 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-10-23 18:52:52.468  INFO 6004 --- [           main] jp.co.musako.Application                 : Started Application in 2.978 seconds (JVM running for 3.454)
Initialize Application Context
call constructor lazyInitializationDemoBean1
lazyInitializationDemoBean1 is first bean
lazyInitializationDemoBean2 is second bean
excludeLazyInitializationDemoBean is third bean

As mentioned above, of the three beans defined in Config.java, only lazyInitializationDemoBean1 is the target of LazyInitialization.

Click here for source code: GitHub --forests-k / spring-boot-lazy-initialization : Spring Boot v2.2.0 lazy-initialization sample

Things to consider when applying Lazy Initialization

The advantage of introducing Lazy Intialization is that it speeds up application startup and it does not waste memory because it initializes when needed.

However, initializing the bean and holding the bean in the container when necessary changes the life cycle of the bean so far, and the maximum number of beans held in the container (= memory occupancy) It may not be visible, so it may be possible that it has an impact on CPU load and load average, that is, you should not over-reliance on Lazy Initialization.

Therefore, it is necessary to consider conducting tests such as temporarily disabling Lazy Initialization in a test environment or an environment equivalent to production.

ref

Recommended Posts

I tried Lazy Initialization with Spring Boot 2.2.0
I tried GraphQL with Spring Boot
I tried Flyway with Spring Boot
I tried Spring.
Spring Boot Introductory Guide I tried [Accessing Data with JPA]
I tried to get started with Swagger using Spring Boot
[I tried] Spring tutorial
I tried Spring Batch
Download with Spring Boot
I wanted to gradle spring boot with multi-project
Generate barcode with Spring Boot
Hello World with Spring Boot
I tried to implement file upload with Spring MVC
Implement GraphQL with Spring Boot
I tried DI with Ruby
Get started with Spring boot
05. I tried to stub the source of Spring Boot
Run LIFF with Spring Boot
SNS login with Spring Boot
I tried to get started with Spring Data JPA
I tried Spring State machine
File upload with Spring Boot
Spring Boot starting with copy
Hello World with Spring Boot
Set cookies with Spring Boot
Use Spring JDBC with Spring Boot
I tried UPSERT with PostgreSQL.
Add module with Spring Boot
Getting Started with Spring Boot
I tried to clone a web application full of bugs with Spring Boot
I tried BIND with Docker
Create microservices with Spring Boot
I wrote a test with Spring Boot + JUnit 5 now
Send email with spring boot
Create an app with Spring Boot 2
I tried using Spring + Mybatis + DbUnit
Database linkage with doma2 (Spring boot)
I tried morphological analysis with MeCab
Spring Boot programming with VS Code
Until "Hello World" with Spring Boot
Get validation results with Spring Boot
I tried to interact with Java
I tried UDP communication with Java
(Intellij) Hello World with Spring Boot
Create an app with Spring Boot
Google Cloud Platform with Spring Boot 2.0.0
Check date correlation with Spring Boot
[Java] LINE integration with Spring Boot
Beginning with Spring Boot 0. Use Spring CLI
I tried customizing slim with Scaffold
Message cooperation started with Spring Boot
Spring Boot gradle build with Docker
I tried Spring Boot introductory guide [Building a RESTful Web Service]
I tried printing a form with Spring MVC and JasperReports 1/3 (JasperReports settings)
I tried printing a form with Spring MVC and JasperReports 3/3 (Spring MVC control)
I tried connecting to MySQL using JDBC Template with Spring MVC
I made a simple search form with Spring Boot + GitHub Search API.
Spring Boot Introductory Guide I tried [Consuming a RESTful Web Service]
Processing at application startup with Spring Boot
I tried using Realm with Swift UI
Hello World with Eclipse + Spring Boot + Maven