我尝试在Spring Boot 2.2.0中使用延迟初始化

Spring Boot版本2.2.0

最新版本的Spring Boot v2.2.0已经发布并成为了GA。

因此,我們將對其中一個功能LazyInitialization進行檢驗。

Spring Boot 2.2.0
发布 v2.2.0.RELEASE · spring-projects/spring-boot · GitHub
Spring Boot 2.2 发行说明 · spring-projects/spring-boot Wiki · GitHub
Spring Boot 参考文档

环境

    • Windows10

 

    • OracleJDK 13(build 13)

 

    Spring Boot 2.2.0 RELEAS

建立项目

“将 Project 设定为 Spring Initializr 的生成。”

spring-initializr.PNG

Gradle 是一种构建工具。

我已确认在使用Spring Initializr创建的Gradle项目中应用了Gradle 5.6.2。

> 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是指在调用了目标Bean之后,才生成由ApplicationContext管理的Bean,而不是在应用程序启动时(即ApplicationContext初始化时)进行生成。

这个机制在之前的版本中也存在,但是从v2.2.0开始,通过将propertyspring.main.lazy-initialization设置为true,可以统一应用延迟初始化。

    application.yml
spring:
  main:
    lazy-initialization: true
    Bean class
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);
    }
}
    config class
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");
    }
}
    main class
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");
    }
}

运行结果

>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

在这里,可以看出以下步骤的处理。

    1. 应用程序启动

在启动后输出”初始化应用程序上下文”

生成Bean

在Bean的构造函数中输出”调用构造函数lazyInitializationDemoBean1″

调用生成的Bean的writer方法

在writer方法中输出”lazyInitializationDemoBean1是第一个Bean”

懒加载的例外应用

在项目中应用LazyInitialization并将特定的Bean排除在LazyInitialization之外,您可以采取以下方式设置spring.main.lazy-initialization=true。

    1. 将@org.springframework.context.annotation.Lazy(false)设置为Bean

懒加载 (Spring Framework 5.2.0.RELEASE API)

在org.springframework.boot.LazyInitializationExcludeFilter中注册要排除的Bean

懒加载排除过滤器 (Spring Boot Docs 2.2.0.BUILD-SNAPSHOT API)

    config class
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適用対象
    @Bean("lazyInitializationDemoBean1")
    public LazyInitializationDemoBean lazyInitializationDemoBean1(){
        return new LazyInitializationDemoBean("lazyInitializationDemoBean1");
    }

    // Lazy Initialization適用対象外
    @Bean("lazyInitializationDemoBean2")
    @Lazy(false)
    public LazyInitializationDemoBean lazyInitializationDemoBean2(){
        return new LazyInitializationDemoBean("lazyInitializationDemoBean2");
    }

    // Lazy Initialization適用対象外
    @Bean
    public ExcludeLazyInitializationDemoBean ExcludeLazyInitializationDemoBean(){
        return new ExcludeLazyInitializationDemoBean("excludeLazyInitializationDemoBean");
    }
}
    main class
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

如上所示,在Config.java文件中定义的三个Bean中,我们可以看到只有lazyInitializationDemoBean1会被懒加载。

这里有源代码:GitHub – forests-k/spring-boot-lazy-initialization
Spring Boot v2.2.0的延迟初始化示例

在应用懒惰初始化时需要考虑的问题

引入惰性初始化的优点在于提高应用程序启动速度,并在需要时进行初始化,不浪费内存。

然而,在必要时初始化Bean并将其保存在容器中,这会导致以前的Bean生命周期的某些变化,而且无法预见容器中最大可能保持的Bean数量(即占用的内存量),这可能会对CPU负载和负载平均值产生影响,因此不能过分依赖LazyInitialization,这是有可能的。

因此,似乎应该考虑在测试环境或类似生产环境中进行一些测试,例如暂时禁用延迟初始化。

盗窃是一种犯罪行为,指的是非法获取他人财物。

    • Lazy Initialization in Spring Boot 2.2

 

    • Spring Boot Reference Documentation

 

    appendix Common Application properties
广告
将在 10 秒后关闭
bannerAds