美文网首页
Spring IOC

Spring IOC

作者: tracyzht | 来源:发表于2017-06-07 00:24 被阅读0次

    1、AbstractApplicationContext.refresh的流程:

    image.png

    2、obtainFreshBeanFactory的调用栈

    image.png

    3、主要过程

    resource定位、加载、解析、注册、实例化和依赖注入

    3.1 Resource定位

    XmlWebApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
    
    image.png
    XmlWebApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader)
    
    image.png
    AbstractBeanDefinitionReader.loadBeanDefinitions
    

    创建Resource对象,然后加载bean

    image.png
    getResourceByPath
    
    image.png

    3.2加载

    在XmlBeanDefinitionReader.loadBeanDefinitions(Resource resource)中实现
    
    image.png

    从resource中获取xml文件的Inputstream,再创建InputSource。真正加载是在doLoadBeanDefinitions里。

    image.png

    DefaultDocumentReader把xml文件解析为Document

    image.png

    3.3解析

    利用DefaultBeanDefinitionDocumentReader把Document对象解析为BeanDefinition,最后BeanDefinition对象集合到封装类BeanDefinitionHolder中

    image.png

    DefaultBeanDefinitionDocumentReader中实际解析document的过程:
    1、如果使用<import>元素来导入外部资源,spring会首先加载外部资源;
    2、如果定义了<Alias>别名,Spring IoC容器将别名元素所定义的别名注册到容器中。
    3、对于既不是<Import>元素,又不是<Alias>元素的元素,即Spring配置文件中普通的<Bean>元素的解析由BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法来实现

    image.png

    BeanDefinitionParseDelegate解析过程

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
       String id = ele.getAttribute(ID_ATTRIBUTE);
       String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
     
       List<String> aliases = new ArrayList<String>();
       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");
          }
       }
     
       if (containingBean == null) {
          checkNameUniqueness(beanName, aliases, ele);
       }
     
       AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
       if (beanDefinition != null) {
          if (!StringUtils.hasText(beanName)) {
             try {
                if (containingBean != null) {
                   beanName = BeanDefinitionReaderUtils.generateBeanName(
                         beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                   beanName = this.readerContext.generateBeanName(beanDefinition);
                   // Register an alias for the plain bean class name, if still possible,
                   // if the generator returned the class name plus a suffix.
                   // This is expected for Spring 1.2/2.0 backwards compatibility.
                   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);
          return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
       }
     
       return null;
    }
    

    3.4注册

    在完成BeanDefinition解析并封装在BeanDefinitionHolder之后,进行注册

    image.png

    实际注册过程由DefaultListableBeanFactory.registerBeanDefinition负责

    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
          throws BeanDefinitionStoreException {
     
       Assert.hasText(beanName, "Bean name must not be empty");
       Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     
       if (beanDefinition instanceof AbstractBeanDefinition) {
          try {
             ((AbstractBeanDefinition) beanDefinition).validate();
          }
          catch (BeanDefinitionValidationException ex) {
             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                   "Validation of bean definition failed", ex);
          }
       }
     
       BeanDefinition oldBeanDefinition;
     
       oldBeanDefinition = this.beanDefinitionMap.get(beanName);
       if (oldBeanDefinition != null) {
          if (!isAllowBeanDefinitionOverriding()) {
             throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                   "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                   "': There is already [" + oldBeanDefinition + "] bound.");
          }
          else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
             // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
             if (this.logger.isWarnEnabled()) {
                this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                      "' with a framework-generated bean definition: replacing [" +
                      oldBeanDefinition + "] with [" + beanDefinition + "]");
             }
          }
          else if (!beanDefinition.equals(oldBeanDefinition)) {
             if (this.logger.isInfoEnabled()) {
                this.logger.info("Overriding bean definition for bean '" + beanName +
                      "' with a different definition: replacing [" + oldBeanDefinition +
                      "] with [" + beanDefinition + "]");
             }
          }
          else {
             if (this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean '" + beanName +
                      "' with an equivalent definition: replacing [" + oldBeanDefinition +
                      "] with [" + beanDefinition + "]");
             }
          }
          this.beanDefinitionMap.put(beanName, beanDefinition);
       }
       else {
          if (hasBeanCreationStarted()) {
             // Cannot modify startup-time collection elements anymore (for stable iteration)
             synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                   Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                   updatedSingletons.remove(beanName);
                   this.manualSingletonNames = updatedSingletons;
                }
             }
          }
          else {
             // Still in startup registration phase
             this.beanDefinitionMap.put(beanName, beanDefinition);
             this.beanDefinitionNames.add(beanName);
             this.manualSingletonNames.remove(beanName);
          }
          this.frozenBeanDefinitionNames = null;
       }
     
       if (oldBeanDefinition != null || containsSingleton(beanName)) {
          resetBeanDefinition(beanName);
       }
    }
    

    最终把beanDefinition存放在beanDefinitionMap中,key是beanName,value是beanDefiniton。

    4、IoC容器的实例化与依赖注入

    SimpleInstantiationStrategy提供了两种方式对bean进行实例化。第一种是利用反射,第二种是利用CGLIB来生成。

    image.png

    5、IoC容器启动(以FileSystemXmlApplicationContext为例)

    FileSystemXmlApplicationContext的构造函数如下,启动了IoC容器

    image.png

    refresh()方法在FileSystemXmlApplicationContext的父类AbstractApplicationContext中实现。在refresh()方法中,最终调用了refreshBeanFactory()方法。
    完整IoC容器启动分析(以FileSystemXmlApplicationContext为例)

    1. FileSystemXmlApplicationContext构造方法调用refresh()方法,这里是载入beanDefinition的入口
    2. refresh()方法在FileSystemXmlApplicationContext的父类AbstractApplicationContext中的实现,调用refreshBeanFactory()方法;
    3. refreshBeanFactory()方法在AbstractApplicationContext的子类AbstractRefreshableApplicationContext中实现,调用了loadBeanDefinition()方法,启动对beanDefinition的载入;
    4. loadBeanDefinition()在AbstractXmlApplicationContext中实现,调用了XmlBeanDefinitionReader的loadBeanDefinitions()方法。
    5. XmlBeanDefinitionReader的loadBeanDefinitions()实现了对于承载beanDefnition定义的xml文件的读入,以I/O的方式。
    6. 读入后,对beanDefinition进行解析。Bean解析采用SAX工具,先按照XML文件格式解析,再按照spring bean的定义解析,在BeanDefinitionParserDelegate.parseBeanDefinitionElement()实现。
    7. 最后对beanDefinition信息进行注册。就是将每个beanDefinition以key =beanName,value = beanDefinition放入一个hashMap中,在DefaultListenableFactoty.RegisterBeanDefinition()中实现。
      经过IoC容器的初始化后,IoC容器持有beanDefintion,为依赖注入bean即调用getBean()方法奠定了基础。

    相关文章

      网友评论

          本文标题:Spring IOC

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