You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot:如何正确测试@Lazy注解Bean的懒加载行为?

@Lazy注解的Bean注册与懒加载测试问题

场景复现

配置类中通过@Bean+@Lazy定义了依赖DependencyBean的SomeBean:

@Configuration
public class LazyConfig
{
    @Bean
    @Lazy
    public SomeBean someBean(final DependencyBean dependencyBean)
    {
        return new SomeBean(dependencyBean);
    }
}

使用ApplicationContextRunner编写测试,期望容器未加载SomeBean,但测试失败:

class LazyConfigTest
{
  ApplicationContextRunner runner = new ApplicationContextRunner()
    .withUserConfiguration(LazyConfig.class);

  @Test
  void testNoLazyIsLoaded()
  {
    runner.run(context -> {
      org.assertj.core.api.Assertions.assertThat(context).getBeanNames(SomeBean.class).isEmpty();
            // > Expecting empty but was: ["someBean"]
      org.assertj.core.api.Assertions.assertThat(context).doesNotHaveBean(SomeBean.class);
            // > Expecting not to have, but found: <["someBean"]>
    });
  }
}

尝试主动获取该Bean时,因依赖缺失报错:

context.getBean(SomeBean.class);
// > Error creating bean with name 'someBean' defined in org.lucasvc.lazy.config.LazyConfig: Unsatisfied dependency expressed through method 'someBean' parameter 0: No qualifying bean of type 'org.lucasvc.lazy.DependencyBean' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

疑问

  1. 加了@Lazy注解的Bean也会被注册到上下文吗?
  2. 如何正确测试@Lazy的懒加载行为?

解答

1. @Lazy不会阻止Bean注册到上下文

@Lazy注解的作用是延迟Bean的实例化,而非阻止Bean定义的注册。Spring容器启动时,会正常解析@Bean注解,将SomeBean的定义加载到上下文当中,所以getBeanNames(SomeBean.class)能查询到对应的Bean名称,doesNotHaveBean断言失败也是因为上下文已存在该Bean的注册信息。

此时Bean只是未被实例化,它的定义是存在的;只有当第一次尝试获取该Bean(比如调用getBean(SomeBean.class))时,Spring才会触发实例化流程,此时才会检查依赖是否存在——这也是主动获取Bean时出现依赖缺失报错的原因。

2. 正确测试@Lazy的懒加载行为

验证懒加载的核心是检查Bean是否尚未被实例化,而非检查Bean定义是否存在。可以通过以下两种方式实现:

方式一:验证Bean的懒加载配置与实例状态

通过获取BeanFactory,检查Bean定义的懒加载属性,同时验证Bean是否未被实例化为单例对象:

@Test
void testLazyBeanNotInstantiated() {
    runner.run(context -> {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
        
        // 验证该Bean确实配置了懒加载
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("someBean");
        assertThat(beanDefinition.isLazyInit()).isTrue();
        
        // 验证Bean尚未被实例化(单例池不存在该Bean)
        assertThat(beanFactory.containsSingleton("someBean")).isFalse();
    });
}

方式二:验证实例化触发时机

先确认Bean未实例化,然后主动触发实例化(需确保依赖存在,比如临时注册DependencyBean),再验证实例已存在:

@Test
void testLazyBeanInstantiatedOnDemand() {
    runner.withBean(DependencyBean.class) // 注册依赖Bean
          .run(context -> {
              DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
              
              // 初始状态下Bean未实例化
              assertThat(beanFactory.containsSingleton("someBean")).isFalse();
              
              // 主动获取Bean,触发实例化
              SomeBean someBean = context.getBean(SomeBean.class);
              
              // 验证Bean已实例化
              assertThat(beanFactory.containsSingleton("someBean")).isTrue();
              assertThat(someBean).isNotNull();
          });
}

内容的提问来源于stack exchange,提问作者lucasvc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:23:17