spring框架刚出来的时候,我们基本都是在 xml文件里配置bean的,那么spring框架是如何解析xml 里内容的呢,今天我们就从一句代码着手,一步步来分析。

spring框架的其中一大特性IOC,讲的就是把bean的创建交给spring框架来做,这样能保证类之间互相引用时,不需要 new 一个对象,只需要使用注解注入即可引用对应的类。因此spring框架会把xml里定义的bean实例化。

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("bean.xml"))

首先看 new ClassPathResource("bean.xml") 做了什么。

public ClassPathResource(String path) {
        this(path, (ClassLoader) null);
    }

public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
        Assert.notNull(path, "Path must not be null");
        //对 path 进行修正,比如把 "\\" 转为 "/"
        String pathToUse = StringUtils.cleanPath(path);
        if (pathToUse.startsWith("/")) {
            pathToUse = pathToUse.substring(1);
        }
        this.path = pathToUse;
     //获取当前线程的 ClassLoader
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader()); }

这句代码把配置文件封装为 ClassPathResource,以便于读取。

接下来是  new XmlBeanFactory

//根据提供的resource 加载 bean definition
public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
     //parentBeanFactory 初始值为空
super(parentBeanFactory);  
     //这句才是重点,reader指的是
XmlBeanDefinitionReader
     this.reader.loadBeanDefinitions(resource);
}

 XmlBeanDefinitionReader 的 loadBeanDefinitions

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
     //把 Resource 转为 EncodedResource,用于对资源文件编码处理,当设置了编码属性,spring 会使用相应的编码作为输入流的编码。
return loadBeanDefinitions(new EncodedResource(resource)); } public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<>(4); this.resourcesCurrentlyBeingLoaded.set(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()); }
          //真正的执行代码在这里
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(); } } }
doLoadBeanDefinitions,我删除了一些不重要的catch
//
protected
int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try {
       //加载XML,获取对应的document Document doc
= doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; }catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }

doLoadBeanDefinitions 比较重要的是这句代码
int count = registerBeanDefinitions(doc, resource);

真正的执行在这里DefaultBeanDefinitionDocumentReader 类中的doRegisterBeanDefinitions方法,这个方法的代码如下
BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        preProcessXml(root);
     //真正解析bean标签的地方 parseBeanDefinitions(root,
this.delegate); postProcessXml(root); this.delegate = parent; } 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标签 parseDefaultElement(ele, delegate); }
else {
               //自定义的 bean 标签 delegate.parseCustomElement(ele); } } } }
else { delegate.parseCustomElement(root); } }

这时候我们看到这里才是真正解析xml文件里bean标签的内容。