Spring源码学习之路——Spring中XML解析原理

前言

坚持下去

正文

初识

我先初略的讲述一下,Spring是如何加载XML的?
1.传入需要解析和加载的XML字符串;
2.把该字符串解析后,循环放入AbstractRefreshableConfigApplicationContext类的configLocations数组中;
3.创建出一个BeanFactory工厂;
4.给该BeanFactory创建出一个XML解析器,用于解析XML;
5.用XML解析器,循环解析configLocations数组中的XML;
6.用流的方式加载配置 文件,然后封装成Resource对象;
7.将Resource对象的封装成带编码EncodedResource对象;
8.从EncodedResource中获取到文件流对象,并把流对象封装成InputSource对象,这个对象是JDK种的sax解析对象。;
9.根据自定义标签或者默认标签的标签不同,将标签元素封装成BeanDefinition。

详细的加载过程(注意看代码块中的注释)

解析字符串和加载spring
org.springframework.context.support.ClassPathXmlApplicationContext

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        //这里是去解析字符串(如:spring.xml)
        this.setConfigLocations(configLocations);
        if (refresh) {
        //关键方法,开始加载spring
            this.refresh();
        }

    }

(接解析字符串)
org.springframework.context.support.AbstractRefreshableConfigApplicationContext

//该方法就是去循环数组,并添加到configLocations数组
public void setConfigLocations(String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];

            for(int i = 0; i < locations.length; ++i) {
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }

    }

(接加载spring)
org.springframework.context.support.AbstractApplicationContext
该方法是个典型的模板设计模式,以后会详细介绍spring中的各种设计模式

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            //主要是这里,里面就会去解析XML
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

创建一个BeanFactory
org.springframework.context.support.AbstractRefreshableApplicationContext

protected final void refreshBeanFactory() throws BeansException {
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
        	//这里就是去创建一个BeanFactory
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            //重点在这里,这方法就准备开始将XML转换成BeanDefinition
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

这里创建XML的解析器
org.springframework.web.context.support.XmlWebApplicationContext

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		//用委托模式,创建一个XML解析器
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        //重点又在这,将XML解析器传入到方法中
        this.loadBeanDefinitions(beanDefinitionReader);
    }

加载XML文件
org.springframework.web.context.support.XmlWebApplicationContext

 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
 		//获取需要加载的xml配置文件
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            String[] var3 = configLocations;
            int var4 = configLocations.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String configLocation = var3[var5];
                reader.loadBeanDefinitions(configLocation);
            }
        }

    }

以流的方式加载XML
org.springframework.beans.factory.support.AbstractBeanDefinitionReader

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                Resource resource = resourceLoader.getResource(location);
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                	//用流的方式加载配置文件,然后封装成Resource对象
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //重点:将resources 传入解析成BeanDefinition
                    loadCount = this.loadBeanDefinitions(resources);
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }

从EncodedResource中获取到文件流对象,并把流对象封装成InputSource对象,这个对象是JDK种的sax解析对象。
org.springframework.beans.factory.xml.XmlBeanDefinitionReader

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        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 {
            	//获取Resource对象中的xml文件流对象
                InputStream inputStream = encodedResource.getResource().getInputStream();

                try {
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
                    //重点:开始去解析XML
                    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;
        }
    }

从dom对象中拿到里面的标签元素封装成BeanDefinition
org.springframework.beans.factory.xml.XmlBeanDefinitionReader

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
        	//将inputSource对象封装成DOC对象
            Document doc = this.doLoadDocument(inputSource, resource);
            //重点:根据解析出来的DOC对象,将里面的标签元素封装成BeanDefinition
            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);
        }
    }

根据标签不同解析,分别解析标签元素
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader

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)) {
                    	//默认标签
                        this.parseDefaultElement(ele, delegate);
                    } else {
                    	//自定义标签
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }

    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值