Spring @Lazy

By default, Spring creates all singleton beans eagerly at the startup/bootstrapping of the application context. The reason behind this is simple: to avoid and detect all possible errors immediately rather than at runtime.

However, there’re cases when we need to create a bean, not at the application context startup, but when we request it.

@Lazy has an argument named value with the default value of true. It is useful to override the default behavior.

Lazy Initialization

The @Lazy annotation has been present since Spring version 3.0.

This annotation behaves differently depending on where we exactly place it.
1、a @Bean annotated bean factory method, to delay the method call (hence the bean creation)
2、a @Configuration class and all contained @Bean methods will be affected
3、a @Component class, which is not a @Configuration class, this bean will be initialized lazily
4、a @Autowired constructor, setter, or field, to load the dependency itself lazily (via proxy)


@Configuration Class

When we put @Lazy annotation over the @Configuration class, it indicates that all the methods with @Bean annotation should be loaded lazily.

This is the equivalent for the XML based configuration’s default-lazy-init=“true“ attribute.

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

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

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

@Test
public void givenLazyAnnotation_whenConfigClass_thenLazyAll() {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.class);
    ctx.refresh();
    ctx.getBean(Region.class);
    ctx.getBean(Country.class);
}

As we see, all beans are created only when we request them for the first time:

Bean factory for ...AnnotationConfigApplicationContext: 
...DefaultListableBeanFactory: [...];
// application context started
Region bean initialized
Country bean initialized

@Bean method

# To apply this to only a specific bean
@Configuration
@ComponentScan(basePackages = "com.lazy")
public class AppConfig {

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

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

With @Autowired

# The bean that we want to load lazily
@Lazy
@Component
public class City {
    public City() {
        System.out.println("City bean initialized");
    }
}

public class Region {
    @Lazy
    @Autowired
    private City city;

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

    public City getCityInstance() {
        return city;
    }
}

# Note, that the @Lazy is mandatory `n both places
@Test
public void givenLazyAnnotation_whenAutowire_thenLazyBean() {
    // load up ctx appication context
    Region region = ctx.getBean(Region.class);
    region.getCityInstance();
}

Here, the City bean is initialized only when we call the getCityInstance() method.

参考:A Quick Guide to the Spring @Lazy Annotation

你可能感兴趣的:(框架,spring,java,后端)