Spring Bean生命周期-obtainFreshBeanFactory(三)-阿里云开发者社区

开发者社区> 开发与运维> 正文

Spring Bean生命周期-obtainFreshBeanFactory(三)

简介: 初始化ApplicationContext的时候,如果设置了自动刷新标志,会执行AbstractApplication的refresh方法,我们前篇文章提到了它的prepareRefresh方法,接下来执行的就是obtainFreshBeanFactory。

初始化ApplicationContext的时候,如果设置了自动刷新标志,会执行AbstractApplication的refresh方法,我们前篇文章提到了它的prepareRefresh方法,接下来执行的就是obtainFreshBeanFactory。

注释为:

告诉子类刷新内部的bean factory,返回新的BeanFactory实例

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

obtainFreshBeanFactory代码分析

  1. 刷新BeanFactory,关闭之前的bean factory,然后初始化新的bean factory
    
    protected final void refreshBeanFactory() throws BeansException {
       // 锁beanFactoryMonitor,判断beanFactory是否为null 
        if (hasBeanFactory()) {
           //如字面意思,销毁Bean,关闭BeanFactory
            destroyBeans();
            closeBeanFactory();
        }
        try {
           // 创建BeanFactory,设置Id,自定义BeanFactory中设置了allowBeanDefinitionOverriding,allowCircularReferences
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            
            //加载Bean的定义,比较重要的方法
            loadBeanDefinitions(beanFactory);
            
            // 赋值BeanFactory
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }
  1. getBeanFactory主要是简单的返回 this.beanFactory 成员,没有做额外的处理
// 简单的返回beanFactory
public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call 'refresh' before accessing beans via the ApplicationContext");
            }
            return this.beanFactory;
        }
    }

loadBeanDefinitions分析

ApplicationContext中创建的beanFactory默认是DefaultListableBeanFactory。

protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }
  1. loadBeanDefinitions概览
// AbstractXMLApplicationContext.java

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.
        // 主要用来让子类覆盖此方法来实现对reader的自定义设置
        initBeanDefinitionReader(beanDefinitionReader);
        
        // 关键的方法,加载beanDefinitions
        loadBeanDefinitions(beanDefinitionReader);
    }
  1. loadBeanDefinitions中,会根据我们实例化ApplicationContext传入的配置,来使用beanReader来加载。最终都是使用beanReader来从resource中加载bean
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
     // 获取配置的位置,然后加载        // 第一次实例化时,一般加载的是configLocations
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }
  1. beanReader加载配置的方法,看这之前可以先看下AbstractBeanDefinitionReader的构造方法,设置了resourceLoader与environment。
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
     // 获取资源加载器,ResourceLoader(PathMatchingResourcePatternResolver)
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

      //PathMatchingResourcePatternResolver实现了ResourcePatternResolver接口
        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            // 可用资源样式匹配
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                // 加载BeanDefinitions
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        
        else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }
  1. XMLBeanDefinitionReader.loadBeanDefinitions(Resource resource),从指定的XML文件中加载beanDefinitins。
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

      // 使用ThreadLocal保证线程安全
        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        
        // currentResources添加资源
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                
                // doLoadBeanDefinitions,
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }
  1. doLoadBeanDefinitions,实际上从XML文件中加载beanDefinition的类
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
        ...
        // 捕捉异常
}       
  1. registerBeanDefinitions,从文档中(DOM对象)注册bean
// 返回值为本次总共加载了多少了bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

   //beanDefinition对象存储在beanDefinitionMap中
    public int getBeanDefinitionCount() {
        return this.beanDefinitionMap.size();
    }

真正的从XML文件中加载Bean过程比较重要,是Bean生命周期的关键部分,我们留在下次再讲。

TODO

  • ResourceEntityResolver
  • PathMatchingResourcePatternResolver
  • PathMatchingResourcePatternResolver.getResources方法,内部有查找资源的方法

总结

这里讲解了obtainBeanFactory方法,内部会先刷新BeanFactory,刷新的同时会进行初次的加载beanDfinition,内部涉及流程较多,下次一起看doRegisterBeanDefinitions方法。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章