1.概述

默认情况下,Spring在启动/引导应用程序上下文时会主动的创建所有单例bean。

其背后的原因很简单:立即创建可以检测所有可能的错误·,而不是在运行时被发现。

但是,在某些情况下,我们并不希望在应用程序上下文启动是创建Bean, 而是在请求它的时候创建。

在本文中,我们将讨论Spring的@Lazy注解。

2.延迟初始化

@Lazy注释在Spring 3.0 引入的。

有几种方法可以告诉IoC容器延迟初始化bean。

2.1 @Configuration类

当我们在被@Configuration注释的类上放置@Lazy注解时,表明所有带有@Bean注解的方法都应延迟加载。

这等效于基于XML的配置的default-lazy-init="true" 属性。

比如:

@Lazy
@Configuration
@ComponentScan(basePackages = "com.ripjava.lazy")
public class AppConfig {

    @Bean
    public Region getRegion(){
        return new Region();
    }

    @Bean
    public Country getCountry(){
        return new Country();
    }
}

让我们来测试一下:

@Test
public void test_LazyConfiguration() {
  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
  ctx.register(AppConfig.class);
  System.out.println("before refresh");
  ctx.refresh();
  System.out.println("after refresh");
  ctx.getBean(Region.class);
  ctx.getBean(Country.class);
}

控制台输出如下:

before refresh
after refresh
Region bean initialized
Country bean initialized

如果仅应用于特定的bean,让我们从注释@Configuration类中删除*@Lazy*。

@Bean
@Lazy(true)
public Region getRegion(){
    return new Region();
}

控制台输出如下:

before refresh
Country bean initialized
after refresh
Region bean initialized

2.2 使用@Autowired

在继续之前,请查看这些文章了解的@Autowired@Component注解。

在这里,我们创建一个延迟初始化的Bean,然后在另外一个非延迟初始化的Bean中引用。

延迟初始化的Bean:

@Lazy
@Component
public class City {

    public City() {
        System.out.println("City bean initialized");
    }

    public void test(){
        System.out.println("test");
    }
}

另外一个非延迟初始化的Bean:

public class Region {
 
    @Lazy
    @Autowired
    private City city;
 
    public Region() {
        System.out.println("Region bean initialized");
    }
 
    public City getCityInstance() {
        return city;
    }
}

请注意,@Lazy在两个地方都是必需的。

City类上使用@Component注解,并在Region类中使用@Autowired引用它。

我们来测试一下:

@Test
public void test_LazyAutowired() {
  AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
  ctx.register(AppConfig.class);
  System.out.println("before refresh");
  ctx.refresh();
  System.out.println("after refresh");
  Region region = ctx.getBean(Region.class);
  System.out.println("before getCityInstance");
  region.getCityInstance();
  System.out.println("after getCityInstance");
  region.getCityInstance().test();
}

控制台输出如下:

before refresh
Country bean initialized
after refresh
Region bean initialized
before getCityInstance
after getCityInstance
City bean initialized
test

在这个示例中,只有在我们调用test()方法才会初始化。

6. 总结

在文中,我们学习了Spring 的@Lazy注解的基础知识。还演示了它的使用用法。

最后,往常一样,代码可以在Github上找到。