获取BeanFactory
obtainFreshBeanFactory()方法从字面理解是获取BeanFactory。之前有说过,ApplicationContext是对BeanFactory功能上的扩展,不但包含了BeanFactory的全部功能,更是在其基础上添加了大量的扩展应用,那么obtainFreshBeanFactory正是实现BeanFactory的地方,也就是经过了这个函数后ApplicationContext就已经拥有了BeanFactory的全部功能。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
该方法将核心实现委托给了refreshBeanFactory:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为了序列化指定id,如果需要的话,让这个BeanFactory从id反序列化到BeanFactory对象
beanFactory.setSerializationId(getId());
// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象和循环依赖
// 以及设置@Autowired 和 @Qualifier 注解解析器 QualifierAnnotationAutowire CandidateResolver
customizeBeanFactory(beanFactory);
// 初始化DocumentReader,并进行XML文件读取及解析
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
我们详细分析上面的每个步骤:
(1)创建DefaultListableBeanFactory
在介绍BeanFactory的时候,不知道是否还有印象,声明方式为:BeanFactory bf = new XmlBeanFactory(“applicationContext.xml”),其中的XmlBeanFactory继承自DafaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性,也就是说DafaultListableBeanFactory是容器的基础。必须首先要实例化,那么在这里就是实例化DefaultListableBeanFactory 的步骤。
(2)指定序列化ID。
(3)定制BeanFactory。
(4)加载BeanDefinition。
(5)使用全局变量记录BeanFactory类实例。
因为DefaultListableBeanFactory 类型的变量beanFactory是函数内的局部变量,所以要使用全局变量记录解析结果。
定制BeanFactory
这里已经开始对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖,是否允许扩展的设置并提供了注解@Qualifier 和 @Autowired的支持。
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性
// 此属性的含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性
// 此属性的含义:是否允许bean之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
//用于@Qualifier 和 @Autowired
beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
}
对于允许覆盖和允许依赖的设置这里只是判断了是否为空,如果不为空需要进行设置,但是并没有看到在哪里进行设置,那么究竟在哪里进行设置呢?还是那句话,使用子类覆盖方法,代码如下:
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String... configLocations) {
super(configLocations);
}
@Override
protected void initPropertySources() {
//super.initPropertySources();
getEnvironment().getRequiredProperty("VAR");
}
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}
设置完后相信已经对于这两个属性的使用有所了解了,对于定制BeanFactory,Spring还提供了另外一个重要的扩展,就是设置AutowrieCandidateResolver,而对于默认的实现并没有过多的逻辑处理。在这里,Spring使用了QualifierAnnotationAutowiredCandidateResolver,设置了这个解析器后Spring就可以支持注解方式的注入了。
加载BeanDefinition
在实现配置文件的加载功能除了我们在第一步中已经初始化的DefaultListableBeanFactory外,还需要XmlBeanDefinitionReader读取XML,那么在这个步骤首先要做的就是初始化XmlBeanDefinitionReader。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// 创建XmlBeanDefinitionReader指定给beanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 对beanDefinitionReader进行环境变量的设置
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
// 对beanDefinitionReader进行设置,可以覆盖
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
在初始化了DefaultListableBeanFactory和XmlBeanDefinitionReader后就可以进行配置文件的读取了。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
使用XmlBeanDefinitionReader的loadBeanDefinitions方法进行配置文件的加载注册相信已经不陌生了,这就是开始BeanFactory的套路了。因为在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所以XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefaultListableBeanFactory中,也就是经过此步骤,DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。