Spring ioc 容器的核心类是 AbstractApplicationContext,入口是 refresh()
方法,该方法是个模板方法,定义了加载到容器的全部过程。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
// 注册 BeanDefinition 到 BeanDefinitionRegistry 中
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
// 将 BeanDefinition 转换为 Bean 实例
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}
finally {
resetCommonCaches();
}
}
}
注入 Spring Bean 的逻辑主要在 refresh()
方法的两个方法中。
invokeBeanFactoryPostProcessors
:注册 BeanDefinition 到 BeanDefinitionRegistry 中;finishBeanFactoryInitialization
:将 BeanDefinition 转换为 Bean 实例;通常使用到的 BeanFactory
类是 DefaultListableBeanFactory
,如下图的继承图所示,它实现了 BeanDefinitionRegistry
类,所以也实现了 BeanDefinitionRegistry#registerBeanDefinition()
方法,该方法将所有的 BeanDefinition 注册到 DefaultListableBeanFactory
中。
注:将 BeanDefinition 注册到了 beanFactory 之后,在这里 Spring 为我们提供了一个扩展的切口,允许我们通过实现接口 BeanFactoryPostProcessor 来插入我们定义的代码。 典型的例子就是:PropertyPlaceholderConfigurer,我们一般在配置数据库的 dataSource 时使用到的占位符的值,就是它注入进去的。
在后面的 finishBeanFactoryInitialization
中,调用了方法DefaultListableBeanFactory.preInstantiateSingletons()
,该方法中会根据注册的 BeanDefinition 信息依此调用 getBean(beanName) ,将 bean 内容实例化。
注:实例化中可能出现循环依赖问题,见本篇《第一章》。