本文已收录于【Spring源码札记专栏】。
前面的文章也提到过,IOC容器初始化过程一般不包含Bean加载的实现。Bean加载一般发生在应用第一次通过getBean向容器索取Bean的时候。但有一个例外:如果在XML文件中为Bean定义了lazy-init属性,那么Bean的加载在IOC容器初始化时就预先完成了,我们将其称为预实例化。预实例化虽然会对容器初始化的性能有一些影响,但却能够提高应用第一次取得Bean的性能。
在上下文的初始化过程中,也就是refresh中的代码实现,可以看到预实例化是整个refresh初始化IoC容器的一个步骤。在AbstractApplicationContext中看一下refresh的实现。
@Override
public void refresh() throws BeansException, IllegalStateException {
...
...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
...
...
}
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
...
...
beanFactory.preInstantiateSingletons();
...
...
}
在finishBeanFactoryInitialization的方法中,封装了对lazy-init属性的处理,实际的处理是在DefaultListableBeanFactory这个基本容器的preInstantiateSingletons方法中完成的。
@Override
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
((SmartFactoryBean<?>) factory).isEagerInit(),
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}