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.
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)
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
# 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();
}
}
# 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