Spring IOC refresh()方法——加载BeanFactory

获取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已经包含了所有解析好的配置。

猜你喜欢

转载自blog.csdn.net/yp1125/article/details/79963846