目录
AnnotationConfigApplicationContext是Spring用来加载注解配置的ApplicationContext,它是如何加载所有的bean,与ClassPathXmlApplicationContext有什么区别,让我们接下来揭开它的神秘面纱。
一、版本:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
二、类图
三、时序图
四、源码剖析
4.1 初始化IOC容器
目标类:ClassPathXmlApplicationContext
// new ClassPathXmlApplicationContext("applocationContext.xml")
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
4.2 设置配置文件路径
目标类:AbstractRefreshableConfigApplicationContext
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
4.2 刷新IOC容器
目标类:AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备此上下文以进行刷新,设置其启动日期和活动标志,以及执行属性源的任何初始化。
prepareRefresh();
// 告知子类刷新Bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册IOC的后置处理器和类加载器
prepareBeanFactory(beanFactory);
try {
// 允许调用容器子类Bean工厂进行后处理, 如BeanPostProcessor
postProcessBeanFactory(beanFactory);
// 调用容器中注册的Bean工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的处理器
registerBeanPostProcessors(beanFactory);
// 初始化容器消息源
initMessageSource();
// 为容器初始化事件多播器。
initApplicationEventMulticaster();
// 在特定容器子类中初始化其他特殊Bean
onRefresh();
// 检查Bean监听者并注册
registerListeners();
// 实例化所有剩余的(非@Lazy)单例。
finishBeanFactoryInitialization(beanFactory);
// 最后一步:广播完成事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的单例, 避免资源浪费。
destroyBeans();
// 重置标志位:active
cancelRefresh(ex);
throw ex;
}
finally {
// 重置Spring缓存,如:不再需要单例Bean的元数据信息...
resetCommonCaches();
}
}
}
4.3 刷新Bean工厂
目标类:AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新Bean工厂
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
4.4 刷新BeanFactory
目标类:AbstractRefreshableConfigApplicationContext
// 覆盖AbstractApplicationContext的抽象方法
@Override
protected final void refreshBeanFactory() throws BeansException {
// 销毁已存在的beanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 加载xml定义的beanDefinition信息
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for "
+ getDisplayName(), ex);
}
}
4.5 创建工厂
目标类:AbstractRefreshableConfigApplicationContext
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
4.6 加载Xml中定义的Bean信息
// 覆盖AbstractRefreshableConfigApplicationContext类的抽象方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader, 用于读取XML中定义的Bean配置
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 配置beanDefinitionReader的加载资源环境
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化beanDefinitionReader, 并且加载BeanDefinition信息
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
五、简化IOC启动源码
package com.ioteye.spring.annotation.xml;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import java.util.Date;
@Slf4j
public class XmlIOCStartup {
public static void main(String[] args) {
// classpath资源加载器
ClassPathResource resource = new ClassPathResource("spring.xml");
// 默认的BeanFactory
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 读取xml BeanDefinition的阅读器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 加载配置文件的定义
reader.loadBeanDefinitions(resource);
// 读取容器Bean
Date date = factory.getBean(Date.class);
log.info("bean = {}", date);
}
}