1.SpringIOC执行流程

精选自http://cmsblogs.com/?p=2790

ClassPathResource resource = new ClassPathResource("bean.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);

这段代码是 Spring 中编程式使用 IOC 容器,通过这四段简单的代码,我们可以初步判断 IOC 容器的使用过程。

  • 获取资源
  • 获取 BeanFactory
  • 根据新建的 BeanFactory 创建一个BeanDefinitionReader对象,该Reader 对象为资源的解析器
  • 装载资源 整个过程就分为三个步骤:资源定位、装载、注册,如下:

资源定位。我们一般用外部资源来描述 Bean 对象,所以在初始化 IOC 容器的第一步就是需要定位这个外部资源。

装载。装载就是 BeanDefinition 的载入。BeanDefinitionReader 读取、解析 Resource 资源,也就是将用户定义的 Bean 表示成 IOC 容器的内部数据结构:BeanDefinition。在 IOC 容器内部维护着一个 BeanDefinition Map 的数据结构,在配置文件中每一个 都对应着一个BeanDefinition对象。

注册。向IOC容器注册在第二步解析好的 BeanDefinition,这个过程是通过 BeanDefinitionRegistry 接口来实现的。在 IOC 容器内部其实是将第二个过程解析得到的 BeanDefinition 注入到一个 HashMap 容器中,IOC 容器就是通过这个 HashMap 来维护这些 BeanDefinition 的。在这里需要注意的一点是这个过程并没有完成依赖注入,依赖注册是发生在应用第一次调用 getBean() 向容器索要 Bean 时。当然我们可以通过设置预处理,即对某个 Bean 设置 lazyinit 属性,那么这个 Bean 的依赖注入就会在容器初始化的时候完成。

1. 核心入口xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);

2. 把Resource封装为EncodedResource,调用重载函数loadBeanDefinitions

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

3. 在解析xml之前做准备工作

  • 获取已经加载过的资源
  • 将当前资源加入记录中
  • 获取流,真正执行解析工作
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }
        // 获取已经加载过的资源
        Set 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 {
            // 从 EncodedResource 获取封装的 Resource 并从 Resource 中获取其中的 InputStream
            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();
            }
        }
    }

4. doLoadBeanDefinitions做了两件事,一件事是解析xml,获取document对象,另外一个是将获取的document对象注册到map中

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            // 获取 Document 实例
            Document doc = doLoadDocument(inputSource, resource);
            // 根据 Document 实例****注册 Bean信息
            return registerBeanDefinitions(doc, resource);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (SAXParseException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
        }
        catch (SAXException ex) {
            throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                    "XML document from " + resource + " is invalid", ex);
        }
        catch (ParserConfigurationException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Parser configuration exception parsing XML from " + resource, ex);
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "IOException parsing XML document from " + resource, ex);
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(resource.getDescription(),
                    "Unexpected exception parsing XML document from " + resource, ex);
        }
    }

5.加载Document

getValidationModeForResource(resource)会根据不同的验证模式,来解析Spring的xml,一般验证模式主要分为两种一种是dtd,一种是xsd,大多数人多多少少都见过,如果,没有dtd或者xsd约束,会报错。
DTD缺点:

  • 没有采用xml格式,而是定义了一套自己的格式,解析器重用很差
  • 约束能力弱
  • DTD扩展能力差
  • 正则表达能力描述有限
    XSD优势:
  • 基于xml,没有语法约束
  • 可以基于xml解析,所以解析有优势
  • 数据类型丰富
  • 支持命名空间
  • 支持属性组
    protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

6. 注册得到的Document对象

  • 创建了BeanDefinitionDocumentReader对象
  • 获取已经获得的BeanDefinition对象
  • 注册Document对象
  • 获取获得刚刚注册了多少BeanDefinition对象
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

7.开启注册之旅documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

实现类在DefaultBeanDefinitionDocumentReader.java类中

  • 获取Document的根节点
  • 将根节点注册
    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
    }

解析分为前处理,中处理,后处理

    protected void doRegisterBeanDefinitions(Element root) {
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
              // 处理 profile
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

      // 解析前处理
        preProcessXml(root);//空实现,交给子类实现
        // 解析
        parseBeanDefinitions(root, this.delegate);
        // 解析后处理
        postProcessXml(root);//空实现

        this.delegate = parent;
    }

8.protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

最终解析动作落地在两个方法处:parseDefaultElement(ele, delegate)delegate.parseCustomElement(root)。我们知道在 Spring 有两种 Bean 声明方式:

  • 配置文件式声明:
  • 自定义注解方式:
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)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
    }

9. parseDefaultElement(ele, delegate);做了四件事:

  • 对 import 标签的解析
  • 对 alias 标签的解析
  • 对 bean 标签的解析
  • 对 beans 标签的解析
 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
       // 对 import 标签的解析
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        // 对 alias 标签的解析
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        // 对 bean 标签的解析
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        // 对 beans 标签的解析
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

10.对import解析

  • 获得resource的路径
  • 调用XMLBeanDefinitionReader的loadBeanDefinitions进行Bean初始化

11.protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)对Bean的处理

  • 调用 BeanDefinitionParserDelegate.parseBeanDefinitionElement() 进行元素解析,解析过程中如果失败,返回 null,错误由 ProblemReporter 处理。如果解析成功则返回 BeanDefinitionHolder 实例 bdHolder。 - --- -- BeanDefinitionHolder 为持有 name 和 alias 的 BeanDefinition。
  • 若实例 bdHolder 不为空,则调用 BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired() 进行自定义标签处理
  • 解析完成后,则调用 BeanDefinitionReaderUtils.registerBeanDefinition() 对 bdHolder 进行注册
    发出响应事件,通知相关的监听器,完成 Bean 标签解析
 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        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);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

12. parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)

这个方法还没有对 Bean 标签进行解析,只是在解析动作之前做了一些功能架构,主要的工作有:

  • 解析 id、name 属性,确定 alias 集合,检测 beanName 是否唯一
  • 调用方法 parseBeanDefinitionElement() 对属性进行解析并封装成 GenericBeanDefinition 实例 beanDefinition
  • 根据所获取的信息(beanName、aliases、beanDefinition)构造 BeanDefinitionHolder 实例对象并返回。
   public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        // 解析 ID 属性
        String id = ele.getAttribute(ID_ATTRIBUTE);
        // 解析 name 属性
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        // 分割 name 属性
        List aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }

        // 检查 name 的唯一性
        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        // 解析 属性,构造 AbstractBeanDefinition
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            // 如果 beanName 不存在,则根据条件构造一个 beanName
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Neither XML 'id' nor 'name' specified - " +
                                "using generated bean name [" + beanName + "]");
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);

            // 封装 BeanDefinitionHolder
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

13.public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean)

解析完所有的Bean

   public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        // 解析 class 属性
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        String parent = null;

        // 解析 parent 属性
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {

            // 创建用于承载属性的 GenericBeanDefinition 实例
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            // 解析默认 bean 的各种属性
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

            // 提取 description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

            // 解析元数据
            parseMetaElements(ele, bd);

            // 解析 lookup-method 属性
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

            // 解析 replaced-method 属性
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            // 解析构造函数参数
            parseConstructorArgElements(ele, bd);

            // 解析 property 子元素
            parsePropertyElements(ele, bd);

            // 解析 qualifier 子元素
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

你可能感兴趣的:(1.SpringIOC执行流程)