美文网首页
Spring源码学习

Spring源码学习

作者: 大树8026 | 来源:发表于2019-02-08 20:16 被阅读0次

一、深入以下代码分析过程

    BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));

1、通过ClassPathResource获得配置文件封装。
1.1 ClassPathResource为Resource的一种接口实现,可对资源文件进行管理。而Resource接口又是继承java的InputStreamResource,扩展了InputStreamResource的功能,如检查当前资源是否存在,当前资源是否可读等。
1.2 ClassPathResource的getInputStream也可了解一下:
通过class或者classLoader提供的底层方法进行调用

public InputStream getInputStream() throws IOException {
    InputStream is;
    if (this.clazz != null) {
        is = this.clazz.getResourceAsStream(this.path);
    } else {
        is = this.classLoader.getResourceAsStream(this.path);
    }
    if (is == null) {
        throw new FileNotFoundException(this.getDescription() + " cannot be opened because it does not exist");
    } else {
        return is;
    }
}

2、通过XmlBeanDefinitionReader加载资源

public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader;

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

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

this.reader.loadBeanDefinitions(resource)这一步是资源加载的正真实现。在这步的方法调用中会执行一下代码,这些是关键:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
    try {
//获取xml文件验证格式
        int validationMode = this.getValidationModeForResource(resource);
//获得document对象
        Document doc = this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, validationMode, this.isNamespaceAware());
//注册bean
        return this.registerBeanDefinitions(doc, resource);

2.1 xml文件格式,了解即可。
代码int validationMode = this.getValidationModeForResource(resource);获取验证模式,就是获取xml文件的格式
DTD:全称为Document Type Definition 是一种xml文件约束语言
XSD:全称为XML Schemas Definition

2.2 获得Document对象
代码Document doc = this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, validationMode, this.isNamespaceAware());获得document对象是封装的DefaultDocumentLoader采用SAX解析方法,源码还是可以看懂的;
另外值得看一下的是this.getEntityResolver()方法,这个方法的作用是给项目本身提供一个寻找DTD声明的方法。验证文件默认的加载方式是通过URL在网络上下载,会造成延迟,用户体验也不好,一般都是讲验证文件放在自己的工程里。

2.3 初步探索解析以及注册BeanDefinitions

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // Read document based on new BeanDefinitionDocumentReader SPI.
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

this.registerBeanDefinitions(doc, resource);在这个方法中,重要的目的之一是提取document的root,然后将其作为参数传入registerBeanDefinitions()继续注册。

接下来的代码是registerBeanDefinitions()

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    Element root = doc.getDocumentElement();
    BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
    preProcessXml(root);
    parseBeanDefinitions(root, delegate);
    postProcessXml(root);
}

parseBeanDefinitions(root, delegate);

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                      //默认标签的解析方法 形如<bean id="test" Class="ss.java">
                    parseDefaultElement(ele, delegate);
                }
                else {
                     //自定义标签解析 形如<tx:annotation-driven>
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

注:面向设计方法学中常说的一句话,一个类要么被继承,要么急用final修饰。

未完待续 。。。

相关文章

网友评论

      本文标题:Spring源码学习

      本文链接:https://www.haomeiwen.com/subject/kbvnsqtx.html