阅读spring源码,能学习到很多设计思想,自己实际工作中也经常使用到了spring技术,但仅仅是停留在使用阶段,这次有机会去深入学习,源码分析是一件非常困难的事,自己能力水平有限,下文只是在别人的理解基础上学习。

概念:
    对象阶段:
    java对象经历阶段:对象定义、对象实例化、对象的使用。
    Bean定义方式:
    1)基于xml配置方式
    2)基于annotation配置方式
    3)基于java code配置方式
    4)用户自定义配置方式

这里主要分析Spring Ioc容器解析基于xml配置方式的bean definition的源码实现。
spring大部分功能都是以配置文件作为切入点来实现,所以spring-beans源码分析的思路过程:对xml文档加载和解析并注册bean.


xml加载解析准备阶段

XmlBeanFactory

对资源文件进行封装
  public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        //1)封装资源文件
        //2)获取输入流 
        //3)根据resource 获取inputStream 并构造inputSource
        //4)调用函数
        this.reader.loadBeanDefinitions(resource);
    }
对不同资源文件加载,Resource接口都有相应的实现:
   1)文件:FileSystemResource
   2)classpath资源:ClassPathResource
   3)URL资源:UrlResource
   4)InputStream资源:InputStreamResource
   5)byte数组:ByteArrayResource

XmlBeanDefinitionReader

数据准备阶段
   public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   //EncodedResource将资源文件进行编码处理
   //设置相应的编码属性,spring会使用相应的编码作为输入流的编码
        return loadBeanDefinitions(new EncodedResource(resource));
}

 从Resource获取inputStream来构造inputSource
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

    InputStream inputStream = encodedResource.getResource().getInputStream();
    InputSource inputSource = new InputSource(inputStream);
    if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
        }
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}


  核心处理部分:
  将xml资源文件转换成java对象document

  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //获取对xml文件的验证模式
            int validationMode = getValidationModeForResource(resource);
            //加载xml文件,并得到对应的document
            Document doc = this.documentLoader.loadDocument(
                    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
            return registerBeanDefinitions(doc, resource);
        }


----------
XML验证模式:
 1)DTD:document type definition
      文档结构:元素定义的规则、元素间关系的定义规则、元素可使用的属性、可使用的实体或符号规则

 2)XSD: xml schemas definition
    通过xml schema指定一个xml文档所允许的结构和内容,并可检测一个xml文档是否是有效的,可用通过的xml解析器来解析。

 3)通过判断是否包含doctype yes:DTD no:XSD
   验证方式:XmlValidationModeDetector
    public int detectValidationMode(InputStream inputStream) throws IOException {
        // Peek into the file to look for DOCTYPE.
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        try {
            boolean isDtdValidated = false;
            String content;
            while ((content = reader.readLine()) != null) {
                content = consumeCommentTokens(content);
                //如果读取的行是空或者是注释则略过
                if (this.inComment || !StringUtils.hasText(content)) {
                    continue;
                }
                if (hasDoctype(content)) {
                    isDtdValidated = true;
                    break;
                }
                //读取到<开始符号,验证模式一定会在开始符号之前
                if (hasOpeningTag(content)) {
                    // End of meaningful data...
                    break;
                }
            }
            return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
        }
        catch (CharConversionException ex) {
            // Choked on some character encoding...
            // Leave the decision up to the caller.
            return VALIDATION_AUTO;
        }
        finally {
            reader.close();
        }
    }


----------

将资源文件xml转换成java对象document
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        //解析inputSource
        return builder.parse(inputSource);
    }


----------
  loadDocument方法中参数EntityResolver:
   在SAX应用程序中需要实现自定义处理外部实体,所以需要实现接口并使用setEntityResolver方法向SAX驱动器注册实例。

----------


提取并注册bean
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//设置环境变量        documentReader.setEnvironment(getEnvironment());
    //记录统计前beanDefinition加载的个数
        int countBefore = getRegistry().getBeanDefinitionCount();
    //加载及注册bean
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //返回本次加载的beanDefinition个数
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }


    根据返回的document注册bean信息
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        //提取root 将root作为参数继续beanDefinition的注册
        Element root = doc.getDocumentElement();
        //解析阶段
        doRegisterBeanDefinitions(root);
    }


  解析阶段
protected void doRegisterBeanDefinitions(Element root) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getEnvironment().acceptsProfiles(specifiedProfiles)) {
                return;
            }
        }
       //专门处理解析
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(this.readerContext, root, parent);
        //解析前处理
        preProcessXml(root);
        //解析过程
        parseBeanDefinitions(root, this.delegate);
        //解析后处理
        postProcessXml(root);

        this.delegate = parent;
    }


解析过程
spring的xml配置里面有两种bean声明方式:
1)默认<bean id class/>
2)自定义 <tx:annotation-driven/>
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)) {
                        //spring自定义bean声明方式
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

解析ele nodeName属性,根据解析出的属性名,调用对应的方法
1)元素类型 import alias beans bean
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        //解析bean 调用
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

1)根据自身属性查找BeanDefinitionRegistry对象registry以便得到的Bean注册到一个容器中,供spring统一处理
2)根据beanName查询registry的BeanDefinitionMap容器
 将BeanName 和 BeanDefinition以键值对形式存入beanDefinitionMap容器
 3)spring容器发送一个ReaderEventListener事件
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
       //BeanDefinitionHolder对象 属性:beanName 和String[] aliases
       //解析bean 根据定义的id 和 name属性,并根据解析值设置beanName和aliases值
       //beanName 和 aliases中所有属性名加入到userNames容器中
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
        //
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            } 
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
    //发送事件
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }


根据ele对象 解析其class 和 parent属性
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
}

xml文档解析完并注册bean,放入beanDefinitionMap容器,并发送一个ReaderEventListener事件

在web.xml配置事件监听

<!-- Spring监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>