SpringBoot-Lazy-Initialization

SpringBoot-Testing提到,使用Junit测试SpringBoot项目时,需要使用@SpringBootTest来创建一个Spring容器。而当@SpringBootTest标注的测试类没有使用内嵌@Configuration注解时,会自动使用@SpringBootConfiguration上的配置。

Automatically searches for a @SpringBootConfiguration when nested @Configuration is not used, and no explicit classes are specified.

@SpringBootConfiguration

@SpringBootConfiguration本身是一个合成注解,包含三个注解:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan

其中,@SpringBootConfiguration本身也包含@Configuration,也就是可以在类中通过@bean注解往容器中添加bean@EnableAutoConfiguration为自动配置功能,可以根据pom文件中的依赖,自动向容器中添加bean@ComponentScan组件扫描在SpringBoot-Configuration已经阐述过。

测试往往只针对某个新写的方法,但默认的配置需要将整个应用程序环境都启动,会导致测试程序启动缓慢。一个很直观的解决方法就是使用自定义的配置类,而不是使用默认的主应用的程序环境。

自定义配置类

前面提到@SpringBootTest标注如果带有内嵌@Configuration注解,则不会使用@SpringBootConfiguration上的配置。因此如果需要使用自定义配置类,需要在测试类上添加@Configuration或通过@SpringBootTestclasses属性指定自定义配置类。

1
2
3
@Configuration
static class TestConfiguration {
}

内嵌自定义配置类需要定义在测试类中,并且使用static关键词修饰。

static, non-private, non-final, nested classes annotated with @Configuration

1
@SpringBootTest(classes = TestConfiguration.class)

在自定义配置类中,可以如SpringBoot-Configuration中往容器中添加bean

懒加载

虽然Spring可以通过Auto-configured Tests@ComponentScan来控制自动配置和包扫描规则,来避免不必要的bean导入。

1
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SomeExcludeClass.class})})

但有时很难分清哪些被使用到,哪些没有被使用到,因为bean之间的依赖关系错综复杂。手动去控制自动配置规则和扫描规则太过繁琐。因此更直觉、简便的解决方法是使用懒加载。官方文档

SpringApplication allows an application to be initialized lazily. When lazy initialization is enabled, beans are created as they are needed rather than during application startup. As a result, enabling lazy initialization can reduce the time that it takes your application to start.

懒加载就是在bean被使用时才去实例化,而不是程序一启动就把所有的bean都实例化。因此可以加快程序的启动时间,但会增加用户使用时的延迟。

对于生产中的设备来说,启动时间(只启动一次,往往在半夜没用户使用时)、内存消耗是可以忽略的,但用户体验至关重要。因此生产实践中通常不开启懒加载。

Lazy initialization can be enabled programmatically using the lazyInitialization method on SpringApplicationBuilder or the setLazyInitialization method on SpringApplication. Alternatively, it can be enabled using the spring.main.lazy-initialization property

由于单元测试中容器是自动创建的,lazyInitializationsetLazyInitialization的方法无法执行,因此使用application.properties配置文件的方式是最简单优雅的。

1
spring.main.lazy-initialization=true

如果测试类需要使用独立的配置文件,可以在测试上使用@TestPropertySource注解来指定。

1
@TestPropertySource("classpath:application-test.properties")

总结

@SpringBootTest标注的测试类,默认情况会使用@SpringBootConfiguration的环境设置。

如果需要使用自定义配置可以使用内嵌@Configuration@SpringBootTestclasses属性。

懒加载是个加速程序启动的简单且有效方法。原理是将bean的实例化过程推迟到使用时才实例化。避免了测试过程中大部分bean都用不到,但会被实例化的问题。

在单元测试中,简单且优雅的方式是通过application.properties配置文件来开启懒加载。为了避免影响生产,通常采用测试独立的配置文件,并通过@TestPropertySource来指定。


SpringBoot-Lazy-Initialization
http://dracoyus.github.io/2023/05/04/SpringBoot-Lazy-Initialization/
作者
DracoYu
发布于
2023年5月4日
许可协议