Spring 框架学习(三):IoC 容器
概述
IoC 容器的核心是依赖反转模式。许多应用都是由两个或多个类通过彼此的合作来实现业务逻辑的,这是的每个对象都需要与其合作对象的引用。如果这个获取过程要靠自己实现,那将导致代码高度耦合并且难以测试。在 Spring 中通过把依赖对象的获取交给 IoC 容器来完成,在解耦代码的同时提高了代码的可测试性。
对依赖关系的统一管理,在一定程度上也降低了面向对象系统的复杂性。
在 Spring IoC 容器设计中,有两个主要的容器系列:一个是实现 BeanFactory 接口的简单容器系列,只实现了容器最基本的功能;另一个是 ApplicationContext 应用上下文,它作为容器的高级形态,增加了许多面向框架的特性,同时对应用环境作了许多适配。
BeanFactory 容器
- BeanFactory 定义了容器最基本的接口:获取对象 getBean、判断是否包含 containsBean等。
- HierarchicalBeanFactory 增加了双亲 IoC 容器的管理功能:getParentBeanFactory 接口。
- ConfigurableBeanFactory 增加了设置双亲 IoC 容器的接口:setParentBeanFactory,Bean 后置处理器的添加:addBeanPostProcessor 等等。
- DefaultListableBeanFactory 是一个基本 IoC 容器的实现。
- XmlBeanFactory 相比 DefaultListableBeanFactory 增加了对 xml 配置文件的支持。
ApplicationContext 容器
- ApplicationContext 同样继承了 HierarchicalBeanFactory、BeanFactory 接口。
- ConfigurableWebApplication 也继承了 ConfigurableBeanFactory 接口。
- ApplicationContext 通过继承 MessageSource、ApplicationEventPuhlisher、ResourceLoader 接口,增加了许多高级特性。
- FileSystemXmlApplicationContext 是一个完整的容器实现,从文件系统读取 xml 配置来初始化容器。
容器初始化过程
我们以 FileSystemXmlApplicationContext 为例来查看容器初始化过程,其入口是构造方法:
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 设置双亲容器
super(parent);
setConfigLocations(configLocations);
if (refresh) {
// 读取配置,初始化容器
refresh();
}
}
refresh 方法负责初始化容器的一系列操作,具体有哪些操作看该方法的大纲即可知道:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 做准备操作,加载 placeholder 里配置的环境变量,校验所需环境变量是否全部存在
prepareRefresh();
// 创建 BeanFactory,解析 xml 配置,将 bean 定义加载到 map 中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 一些准备工作,比如设置 ClassLoader、StandardBeanExpressionResolver、BeanPostProcessor
prepareBeanFactory(beanFactory);
try {
// 又设置了一些 BeanPostProcessor
postProcessBeanFactory(beanFactory);
// 调用 BeanFactory 后处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 Bean 的后处理器,前面是 BeanFactory 后处理器,这里是 Bean 的
registerBeanPostProcessors(beanFactory);
// 初始化消息源
initMessageSource();
// 初始化事件机制
initApplicationEventMulticaster();
// 初始化其他特殊的 bean
onRefresh();
// 注册事件 Listener
registerListeners();
// 初始化所有单例 Bean,非单例 Bean 是在 getBean 的时候初始化的
finishBeanFactoryInitialization(beanFactory);
// 发布容器初始化完成事件
finishRefresh();
} catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
比较重要的是以下两步:
- 加载配置,创建 Bean 工厂:obtainFreshBeanFactory。
- 初始化所以单例 Bean:finishBeanFactoryInitialization。
obtainFreshBeanFactory
obtainFreshBeanFactory 加载配置,创建 BeanFactory 的调用顺序如下图所示:
最终调用 BeanDefinitionParserDelegate 类的 parseBeanDefinitionElement 解析 bean 的配置。同时也会调用 parseCustomElement 解析其他配置,该方法最终会调用 NamespaceHandlerSupport 里注册的 BeanDefinitionParser 来解析这些特殊的配置。
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
finishBeanFactoryInitialization
finishBeanFactoryInitialization 这一步会初始化所有单例的 Bean,非单例的 Bean 会在用户调用 getBean 方法的时候被初始化,单例的则是由 Spring 框架来调用 getBean 方法进行实例化。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
// in DefaultListableBeanFactory.java
public void preInstantiateSingletons() throws BeansException {
if (this.logger.isInfoEnabled()) {
this.logger.info("Pre-instantiating singletons in " + this);
}
List<String> beanNames;
synchronized (this.beanDefinitionMap) {
// 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.
beanNames = new ArrayList<String>(this.beanDefinitionNames);
}
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(new PrivilegedAction<Boolean>() {
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 调用 getBean 方法触发 Bean 的创建
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
}
getBean
getBean 方法调用了 createBean,时序图如下:
主要分为以下几步:
- 创建 Bean 实例:createBeanInstance。
- 填充配置的属性值:populateBean。
- 调用初始化方法:initializeBean。
- 注册 Bean 的销毁方法:registerDisposableBeanIfNecessary。
总结
Spring IoC 容器主要负责管理 Bean 的生命周期,Bean 都是放在 BeanFactory 工厂类中管理的,Bean 的配置以 xml 为主。那么初始化的过程,主要就是:
- 创建 BeanFactory。
- 解析 xml 配置,Bean 定义存储到 BeanFactory。
- 实例化 Bean,填充 Bean 的属性值,调用其初始化方法。