spring源码学习笔记整理--XmlBeanFactory的初始化过程

这次稍微了解一下spring创建容器的其中一中方法——XmlBeanFactory(虽然这个方法已经过时了,从源码中可以看出,但是还是觉得有必要了解了解)。

以下是创建容器的代码:

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContextIOC.xml"));

该行代码是Spring加载一个对象的代码,该代码执行的第一步是调用ClasspathResource的构造函数来构造Resource资源文件的实例对象,后续的资源处理就可以使用Resource提供的各种服务,当有了Resource文件之后可以进行XmlBeanFactory的初始化。
 

spring对其内部使用到的资源实现了自己的抽象结构,Resource接口来封装底层资源:

public interface Resource extends InputStreamSource {
    boolean exists();//存在性 
    boolean isReadable();//可读性
    boolean isOpen();//是否处于打开状态
    URL getURL() throws IOException;//获取UrL
    URI getURI() throws IOException; //获取UrI
    File getFile() throws IOException;//获取File
    long contentLength() throws IOException;//获取contentLength(内容长度)
    long lastModified() throws IOException;//获取lastModified(最后修改)
    Resource createRelative(String var1) throws IOException;//基于当前资源创建相对资源的方法,
    String getFilename();//获取文件名(不带路径信息的文件名)
    String getDescription()//在错误处理中打印信息;
}

在日常开发中,资源文件的加载也是经常用到的,可以直接使用spring提供的类来操作,比如希望加载文件时可以使用如下代码:

Resource resource = new ClassPathResource(“beans.xml”);
InputStream inputStream = resource.getInputStream();

有了Resource就可以对所有资源进行统一整理,实现方式也非常简单。

当通过Resource相关类完成对配置文件的封装后,文件的读取工作就交给XmlBeanDefinitionReader来处理了。

了解完spring中将配置文件封装为Resource类型的实例方法后,我们就可以开始正式探寻xmlBeanfactory的初始化过程了

public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
}

该构造方法内部再次就进行了调用内部构造函数:

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);

上面的代码中this.reader.loadBeanDefinitions(resource);才是资源加载的真正实现,XmlBeanDefinitionReader加载数据就是在该方法中完成的。

加载Bean

调用了this.reader.loadBeanDefinitions(resource)之后的处理流程:

  1. 封装资源文件,进入XmlBeanDefinitionReader后首先对Resource使用EncodedResource类进行封装。
  2. 获取输入流,从Resource中获取对应的InputStream并构造InputSource。
  3. 通过构造InputSource实例和Resource实例继续调用doLoadBeanDefinition。

我们来看下loadBeanDefinitions的具体实现过程:

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
}

EncodedResource的作用主要是用于对资源文件的编码进行处理的。其中的主要逻辑在getReader()中。

构造好了encodedResource对象之后,再次转入了可复用方法loadBeanDefinitions(new EncodedResource(resource))。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");//判断encodeResource是否为空
        if (this.logger.isInfoEnabled()) {
            this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
//通过属性来记录已经加载的资源
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
//从encodedResource中获取已经封装的Resource对象并再次从Resource中获取其中的InputStream
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
//InputSource类并不来自于Spring,是org.xml.sax.InputSource
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
//调用核心的方法
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
//关闭资源
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if (((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }
            }
            return var5;
        }
    }
    /**
    即上面的代码首先对传入的resource参数做了封装,是为了考虑Resource可能存在的编码要求的情况,然后通过SAX读取XML文件的方式准备了InputSource对象,最后将准备的数据通过参数传入到核心doLoadBeanDefinitions(InputSource,encodedResource.getResources())。
    */
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            Document doc = this.doLoadDocument(inputSource, resource);
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        } catch (SAXParseException var5) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
        } catch (SAXException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
        } catch (ParserConfigurationException var7) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
        } catch (IOException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
        } catch (Throwable var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
        }
    }
protected Document doLoadDocument (InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
    }
    protected int getValidationModeForResource(Resource resource) {
        int validationModeToUse = this.getValidationMode();
        if (validationModeToUse != 1) {
            return validationModeToUse;
        } else {
            int detectedMode = this.detectValidationMode(resource);
            return detectedMode != 1 ? detectedMode : 3;
        }
    }
  public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
            Document doc = this.doLoadDocument(inputSource, resource);
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            throw var4;
        } catch (SAXParseException var5) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
        } catch (SAXException var6) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
        } catch (ParserConfigurationException var7) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
        } catch (IOException var8) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
        } catch (Throwable var9) {
            throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
        }
    }
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
    }
    protected int getValidationModeForResource(Resource resource) {
        int validationModeToUse = this.getValidationMode();
        if (validationModeToUse != 1) {
            return validationModeToUse;
        } else {
            int detectedMode = this.detectValidationMode(resource);
            return detectedMode != 1 ? detectedMode : 3;
        }
    }
  public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
        int countBefore = this.getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

上面这一长串代码实际上只做了三件事:

  1. 获取对xml文件的验证模式
  2. 加载xml文件并得到对应的Document
  3. 根据Document注册Bean信息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值