Spring源码学习笔记(三):BeanFactory的初始化以及BeanDefinition的加载过程

应用上下文初始化简要流程一文中主要简要的描述了Spring的上下文加载的简要流程。文本是对《应用上下文初始化简要流程》的补充,主要简单的分析了BeanFactory的初始化以及BeanDefinition加载的过程.

我们知道,Spring通过refresh操作重建了ApplicaitonContext,在这个过程中同时也构建了默认的BeanFactory以及加载了BeanDefinitionAbstractApplicationContext类在refresh()方法中调用了obtainFreshBeanFactory, 此方法主要负责重建BeanFactory以及加载BeanDefinition。 下面我们对此方法进行简要分析。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
}

可以看出,此方法的主要逻辑由refreshBeanFactory()方法实现,而refreshBeanFactory()方法的默认实现由AbstractRefreshableApplicationContext来提供,代码如下:

protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

整个refreshBeanFactory()的逻辑是比较清晰的,首先判断是否已存在BeanFactory,如果已存在则销毁:

  • destroyBeans() 清除Bean引用的缓存
  • closeBeanFactory() 释放已创建的BeanFactory

其次调用createBeanFactory建立默认的BeanFactoryDefaultListableBeanFactory————一个基于Bean Definition对象的成熟的Bean工厂;

当BeanFactory建立好之后,进行一项简单的配置customizeBeanFactory(), 以决定在加载BeanDefinition的过程中是否允许循环引用以及是否允许对已有BeanDefinition进行覆写.

最后,方法loadBeanDefinitions()才是重头戏————BeanDefinition的加载过程。

实现loadBeanDefinitions()的子类有多种,如AbstractXmlApplicationContext类提供了基于XML的加载实现,AnnotationConfigWebApplicationContext类提供了在webapp的场景下基于注解配置的加载实现,XmlWebApplicationContext类提供了在webapp场景下基于xml配置的加载实现,XmlPortletApplicationContext提供了在portalet下基于xml配置的加载实现,GroovyWebApplicationContext类提供了基于groovy脚本配置的加载实现。当然也可以自己实现此方法.

此处,我们主要分析基于xml的加载过程。代码如下:

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // 第一行

        beanDefinitionReader.setEnvironment(this.getEnvironment()); //第二行
        beanDefinitionReader.setResourceLoader(this); //第三行
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 第四行

        initBeanDefinitionReader(beanDefinitionReader); // 第五行
        loadBeanDefinitions(beanDefinitionReader); // 第六行
}

第一行代码中实例化了一个XmlBeanDefinitionReader对象,此对象用于读取xml的bean定义,实际上它会将对于xml的处理委托给BeanDefinitionDocumentReader接口。这个对象的构造器需要传入BeanDefinitionRegistry对象,因此此处beanFactory作为一个BeanDefinitionRegistry对象被使用;

XmlBeanDefinitionReader的构造器中调用了它的父抽象类AbstractBeanDefinitionReader的构造器,在这个构造器中,分别为XmlBeanDefinitionReader对象的属性resourceLoaderEnvironment赋值; 如果beanFactory没有实现ResourceLoader接口则会创建PathMatchingResourcePatternResolver实例作为resourceLoader; 如果beanFactory没有实现EnvironmentCapable则会创建StandardEnvironment作为environment; 此处beanFctory的类型为DefaultListableBeanFactory,因此不具备以上条件,故均采用创建对象;

PathMatchingResourcePatternResolver类代理了DefaultResourceLoader,对于通过简单的location获取ResourceDefaultResourceLoader实现,其余复杂location加载Resource由其自己实现;此处采用的设计模式为静态代理

第二行代码为beanDefinitionReaderenvironment赋值,值为StandardEnvironment实例(非web应用的环境)

第三行代码为beanDefinitionReaderresourceLoader赋值,值为当前上下文(当前对象的父类继承了DefaultResourceLoader)

第四行代码为beanDefinitionReaderentityResolver赋值,值为ResourceEntityResolver的实例.此类作为EntityResolver的实现主要是通过ResourceLoader来尝试解析实体引用; 此类又集成了DelegatingEntityResolver所以也可以查找DTD和XSD。

第五行代码initBeanDefinitionReader(beanDefinitionReader)主要是对beanDefinitionReader进行初始化配置,默认是空实现,主要是用于子类覆盖此方法实现自定义XmlBeanDefinitionReader的初始化配置,例如打开或者关闭XML验证,配置不同的XmlBeanDefinitionParser实现

第六行代码loadBeanDefinitions(beanDefinitionReader)就是BeanDefinition的主要加载过程了.它使用指定的XmlBeanDefinitionReader进行加载BeanDefinition. 这个方法仅负责加载或者注册BeanDefinition,而生命周期是通过bean工厂的refreshBeanFactory方法管理. loadBeanDefinitions代码如下:

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值