IOC的初始化流程

Spring如何实现将资源配置通过加载、解析,生成BeanDefinition并注册到IOC容器中的

如何将Bean从XML配置文件中解析后放到IOC容器中的

  • 初始化入口(以XML配置为例):

    ApplicationContext context = new ClassPathXmlApplicationContext("aspects.xml", "daos.xml", "services.xml");
    
  • 查看ClassPathXmlApplicationContext的源码(构造器)

    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, (ApplicationContext)null);
    }
    
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        // 设置Bean资源加载器
        super(parent);
    
        // 设置配置路径
        this.setConfigLocations(configLocations);
    
        // 初始化容器
        if (refresh) {
            this.refresh();
        }
    }
    
  • 设置资源解析器和环境:super(parent)

    调用父类容器AbstractApplicationContext的构造方法,为容器设置好Bean资源加载器

    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        // 默认构造函数初始化容器id, name, 状态 以及 资源解析器
        this();
    
        // 将父容器的Environment合并到当前容器
        this.setParent(parent);
    }
    

    默认构造器初始化容器ID、Name、状态以及资源解析器

    public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.applicationListeners = new LinkedHashSet();
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }
    // Spring资源加载器
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }
    

    通过AbstractApplicationContext的setParent()方法将父容器的Environment合并到当前容器

    public void setParent(@Nullable ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
            }
        }
    }
    
  • 设置配置路径:this.setConfigLocations(configLocations)

    在设置容器的资源加载器之后,接下来ClassPathXmlApplicationContext执行setConfigLocations方法通过调用其父类AbstractRefreshableConfigContext的方法进行对Bean定义资源文件的定位

    public void setConfigLocations(@Nullable 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;
        }
    }
    protected String resolvePath(String path) {
        // 从Environment中解析配置路径
        return this.getEnvironment().resolveRequiredPlaceholders(path);
    }
    
  • 初始化的主体流程:refresh()

    Spring IOC容器对Bean定义资源的载入是从refresh()方法开始的,refresh()是一个模版方法,refresh()方法的作用是:在创建IOC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新创建的IOC容器,refresh的作用类似于对IOC容器的重启,在新建号的容器中对容器进行初始化,对Bean定义资源进行载入
    refresh()方法源码

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
    
            // 初始化配置资源、环境资源
            prepareRefresh();
    
            // 通知子类刷新内部 bean 工厂。
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
            // 初始化Bean工厂
            prepareBeanFactory(beanFactory);
    
            try {
                //允许在上下文子类中对Bean工厂进行后置处理。
                postProcessBeanFactory(beanFactory);
    
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                // 调用在上下文中注册为 bean 的工厂处理器
                invokeBeanFactoryPostProcessors(beanFactory);
    
                // 注册拦截bean创建的bean处理器。
                registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
    
                // 为这个上下文初始化消息源。
                initMessageSource();
    
                // 初始化此上下文的事件监听器。
                initApplicationEventMulticaster();
    
                // 在具体的上下文子类中初始化其他特殊的 Bean。
                onRefresh();
    
                // 检查监听器bean并注册它们。
                registerListeners();
    
                // 实例化所有剩余的(非lazy-init)单例。
                finishBeanFactoryInitialization(beanFactory);
    
                // 最后一步:发布相应的事件。
                finishRefresh();
            }
    
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
    
                // 销毁已经创建的单例,以避免悬空资源。
                destroyBeans();
    
                // 重置“active”标志。
                cancelRefresh(ex);
    
                // 将异常传递给调用者。
                throw ex;
            }
    
            finally {
                // 重置Spring核心中的常见内置缓存,因为我们可能不再需要单例bean的元数据...
                resetCommonCaches();
                contextRefresh.end();
            }
        }
    }
    

    refresh()方法是非常典型的资源类加载处理型的思路

    • 模版方法设计模式,模版方法中使用典型的钩子方法

    • 将具体的初始化加载方法插入到钩子方法之间

    • 将初始化的阶段封装,用来记录当前初始化到什么阶段;常见的设计是xxxPhase/xxxStage;

    • 资源加载初始化有失败等处理,必然是try-catch-finally
      在这里插入图片描述

    • obtainFreshBeanFactory

      AbstractAppplicationContext的obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器加载Bean定义资源文件的过程

      protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
          // 这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
          refreshBeanFactory();
          return getBeanFactory();
      }
      

      AbstractAppplicationContext类只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法

      protected final void refreshBeanFactory() throws BeansException {
          // 如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器
          if (hasBeanFactory()) {
              destroyBeans();
              closeBeanFactory();
          }
          try {
              // 创建DefaultListableBeanFactory,并调用loadBeanDefinitions(beanFactory)装载bean定义
              DefaultListableBeanFactory beanFactory = createBeanFactory();
              beanFactory.setSerializationId(getId());
              customizeBeanFactory(beanFactory); // 对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等 
              loadBeanDefinitions(beanFactory); // 调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器  
              this.beanFactory = beanFactory;
          }
          catch (IOException ex) {
              throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
          }
      }
      
      protected final void refreshBeanFactory() throws IllegalStateException {
        if (this.refreshed) {
          throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        } else {
          this.beanFactory.setSerializationId(this.getId());
          this.refreshed = true;
        }
      }
      
    • loadBeanDefinitions

      AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinition方法,容器真正调用的是其子类AbstractXmlApplicationContext对该方法的实现

      protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
          // 创建XmlBeanDefinitionReader,即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源  
          XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
      
          // 配置上下文的环境,资源加载器、解析器
          beanDefinitionReader.setEnvironment(this.getEnvironment());
          beanDefinitionReader.setResourceLoader(this);
          beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // 为Bean读取器设置SAX xml解析器
      
          // 允许子类自行初始化(比如校验机制),并提供真正的加载方法
          initBeanDefinitionReader(beanDefinitionReader); // 当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
          loadBeanDefinitions(beanDefinitionReader);
      }
      
      protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
          // 加载XML配置方式里的Bean定义的资源
          Resource[] configResources = getConfigResources();
          if (configResources != null) {
              reader.loadBeanDefinitions(configResources);
          }
          // 加载构造函数里配置的Bean配置文件,即{"aspects.xml", "daos.xml", "services.xml"}
          String[] configLocations = getConfigLocations();
          if (configLocations != null) {
              reader.loadBeanDefinitions(configLocations);
          }
      }
      

      由于我们使用ClassPathXmlApplicationContext作为例子分析,因此getConfigResources的返回值为null,因此程序执行reader.loadBeanDefinitions(configLocations)分支。

      XmlBeanDefinitionReader(XML Bean读取器)调用其父类AbstractBeanDefinitionReader的reader.loadBeanDefinitions方法读取Bean定义资源

      public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;
      
        for(int var5 = 0; var5 < var4; ++var5) {
          Resource resource = var3[var5];
          counter += this.loadBeanDefinitions((Resource)resource);
        }
      
        return counter;
      }
      public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        String[] var3 = locations;
        int var4 = locations.length;
      
        for(int var5 = 0; var5 < var4; ++var5) {
          String location = var3[var5];
          counter += this.loadBeanDefinitions(location);
        }
      
        return counter;
      }
      
    • AbstractBeanDefinitionReader读取Bean定义资源

      public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
          throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
          int count;
          //模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源
          if (resourceLoader instanceof ResourcePatternResolver) {
            try {
              //获取到要加载的资源
              Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
              //委派调用其子类的XmlBeanDefinitionReader的方法,实现加载的功能
              count = this.loadBeanDefinitions(resources);
              if (actualResources != null) {
                Collections.addAll(actualResources, resources);
              }
      
              if (this.logger.isTraceEnabled()) {
                this.logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
              }
      
              return count;
            } catch (IOException var6) {
              throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var6);
            }
          } else {
            //如果模式匹配无法匹配到,则只能通过绝对路径URL加载单个资源
            Resource resource = resourceLoader.getResource(location);
            count = this.loadBeanDefinitions((Resource)resource);
            if (actualResources != null) {
              actualResources.add(resource);
            }
      
            if (this.logger.isTraceEnabled()) {
              this.logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
            }
      
            return count;
          }
        }
      }
      

      源码分析该方法做了两件事:

      1. 调用资源加载器的获取资源方法resouceLoader.getResource(location),获取到要加载的资源

      2. 真正执行加载功能的是其子类XmlBeanDefinitionReader的loadBeanDefinitions方法

    • XmlBeanDefinitionReader解析载入的Bean定义资源文件

      //本质上是加载XML配置的Bean
      public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        //加载前确定xml资源的编码类型
        return this.loadBeanDefinitions(new EncodedResource(resource));
      }
      
      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 {
            InputStream inputStream = encodedResource.getResource().getInputStream();
      
            try {
              InputSource inputSource = new InputSource(inputStream);
              if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
              }
              //调用doLoadBeanDefinitions来载入资源数据进行解析
              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;
        }
      }
      
      public int loadBeanDefinitions(InputSource inputSource, String resourceDescription) throws BeanDefinitionStoreException {
        //输入资源和描述性资源统一加载
          return this.doLoadBeanDefinitions(inputSource, new DescriptiveResource(resourceDescription));
      }
      
      protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
          try {
            //将Bean定义资源转换为Document对象
              Document doc = this.doLoadDocument(inputSource, resource);
            //获取到的Document对象来注册Bean的定义资源信息
              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);
          }
      }
      protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        return this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, this.getValidationModeForResource(resource), this.isNamespaceAware());
      }
      
    • DocumentLoader将Bean定义资源转换为Document对象

      DocumentLoader将Bean定义资源转换成Document对象

      public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        //创建文件解析器工厂
        DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
          logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        //创建文档解析器
        DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
        return builder.parse(inputSource);//解析资源
      }
      protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware) throws ParserConfigurationException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);
        //设置解析xml的校验状态
        if (validationMode != 0) {
          factory.setValidating(true);
          if (validationMode == 3) {
            factory.setNamespaceAware(true);
      
            try {
              factory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
            } catch (IllegalArgumentException var6) {
              ParserConfigurationException pcex = new ParserConfigurationException("Unable to validate using XSD: Your JAXP provider [" + factory + "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " + "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
              pcex.initCause(var6);
              throw pcex;
            }
          }
        }
      
        return factory;
      }
      
      protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler) throws ParserConfigurationException {
        DocumentBuilder docBuilder = factory.newDocumentBuilder();
        if (entityResolver != null) {
          docBuilder.setEntityResolver(entityResolver);
        }
      
        if (errorHandler != null) {
          docBuilder.setErrorHandler(errorHandler);
        }
      
        return docBuilder;
      }
      
    • XmlBeanDefinitionReader解析载入的Bean定义资源文件

      解析XML资源文件转换为Document对象后,通过XMLBeanDefinitionReader的doLoadBeanDefinitions方法,首先对载入的Bean定义资源进行Document对象的转换(),然后调用registerBeanDefinitions启动SpringIOC容器对Bean定义的解析过程

      //这里就是按照Spring的Bean语义要求将Bean定义资源解析为容器内部数据结构
      public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
         //创建BeanDefinitionDocumentReader对象,解析Document对象
         BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
         int countBefore = this.getRegistry().getBeanDefinitionCount();
         //解析过程入口,这里依旧采用了委派模式,将具体解析实现的过程交给实现类DefaultBeanDefinitionDocumentReader完成
         documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
         //返回此次解析了多少个对象
         return this.getRegistry().getBeanDefinitionCount() - countBefore;
      }
      protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
         return (BeanDefinitionDocumentReader)BeanUtils.instantiateClass(this.documentReaderClass);
      }
      //创建读取xml文件的上下文
      public XmlReaderContext createReaderContext(Resource resource) {
         return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, this.getNamespaceHandlerResolver());
      }
      

      Bean定义资源的载入解析分为两个过程

      1. 通过调用XML解析器将Bean定义资源文件转换得到Document对象,但是这些Document对象并没有按照Spring的Bean规则进行解析,这是一个载入的过程

      2. 在完成通用的XML解析之后,按照Spring的Bean规则对Document对象进行解析

    • DefaultBeanDefinitionDocumentReader对Bean定义的Document对象解析

      BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类对Document对象进行解析

      public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
         this.readerContext = readerContext;
         this.doRegisterBeanDefinitions(doc.getDocumentElement());
      }
      protected void doRegisterBeanDefinitions(Element root) {
        //任何嵌套的<beans>元素都会导致该方法中的递归。
        //在这里为了正确地传递和保存<beans> default-*属性,跟踪当前(父)委托,该委托可能为null。
        //创造新的(子)委托具有用于回退目的的对父的引用,然后最终将this.delegate重置回其原始(父)引用。
        //这种行为模拟了一堆委托,而实际上不需要一个。
         BeanDefinitionParserDelegate parent = this.delegate;
         this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
         if (this.delegate.isDefaultNamespace(root)) {
           String profileSpec = root.getAttribute("profile");
           if (StringUtils.hasText(profileSpec)) {
             String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
             if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
               if (this.logger.isDebugEnabled()) {
                 this.logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
               }
      
               return;
             }
           }
         }
      
         this.preProcessXml(root);
         //从Document的根元素开始解析Bean定义的Document对象
         this.parseBeanDefinitions(root, this.delegate);
         this.postProcessXml(root);
         this.delegate = parent;
      }
      
    • BeanDefinitionParserDelegate解析Bean定义资源文件生成BeanDefinition

      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);
        }
      
      }
      
      private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        //如果元素节点是<import>导入元素,进行导入解析
         if (delegate.nodeNameEquals(ele, "import")) {
           this.importBeanDefinitionResource(ele);
         } else if (delegate.nodeNameEquals(ele, "alias")) {
           //如果元素节点是<Alias>别名元素,进行别名解析
           this.processAliasRegistration(ele);
         } else if (delegate.nodeNameEquals(ele, "bean")) {
           //如果元素节点<Bean>元素,按照Spring的Bean规则解析元素
           this.processBeanDefinition(ele, delegate);
         } else if (delegate.nodeNameEquals(ele, "beans")) {
           //如果元素节点<Bean>元素,即它是嵌套类型,就会进行递归解析
           this.doRegisterBeanDefinitions(ele);
         }
      }
      
      //解析各种xml元素,生成BeanDefinition
      protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
          bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      
          try {
            //注册最终的装饰实例
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
          } catch (BeanDefinitionStoreException var5) {
            this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
          }
      
          this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
      }
      
    • 解析过后的BeanDefinition在IoC容器中的注册

      Document对象的解析后得到封装BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IOC容器注册解析的Bean。

      //通过BeanDefinitionRegistry将BeanDefinitionHolder注册到BeanFactory
      public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        //在唯一name下注册bean定义。
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        //如果name有别名,就要注册name的别名
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
          String[] var4 = aliases;
          int var5 = aliases.length;
      
          for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            registry.registerAlias(beanName, alias);
          }
        }
      }
      

      当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正完成注册功能的是DefaultListableBeanFactory。

    • DefaultListableBeanFactory向IoC容器注册解析后的BeanDefinition

      IOC容器的本质就是一个BeanDefinitionMap,注册就是将BeanDefinition对象put到Map中

      //Bean定义对象的映射,由Bean的name控制
      private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
      //从Bean name映射到合并的BeanDefinitionHolder
      private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap(256);
      
      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 var8) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8);
          }
        }
      
        BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        //如果已经注册过了
        if (existingDefinition != null) {
          //检查是否可以覆盖
          if (!this.isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
          }
      
          if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (this.logger.isInfoEnabled()) {
              this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }
          } else if (!beanDefinition.equals(existingDefinition)) {
            if (this.logger.isDebugEnabled()) {
              this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
            }
          } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]");
          }
          //覆盖操作
          this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
          if (this.hasBeanCreationStarted()) {
            //无法再修改启动时间的集合元素,用于稳定迭代
            synchronized(this.beanDefinitionMap) {
              this.beanDefinitionMap.put(beanName, beanDefinition);
              List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
              updatedDefinitions.addAll(this.beanDefinitionNames);
              updatedDefinitions.add(beanName);
              this.beanDefinitionNames = updatedDefinitions;
              this.removeManualSingletonName(beanName);
            }
          } else {
            //仍然处于启动注册的阶段
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.removeManualSingletonName(beanName);
          }
          //重置所有已经注册过的BeanDefinition的缓存
          this.frozenBeanDefinitionNames = null;
        }
      
        if (existingDefinition == null && !this.containsSingleton(beanName)) {
          if (this.isConfigurationFrozen()) {
            this.clearByTypeCache();
          }
        } else {
          this.resetBeanDefinition(beanName);
        }
      
      }
      

      到这里,Bean定义资源文件中配置的Bean被解析后,已经注册到IOC容器中,IOC容器统一管理这些Bean实例,真正完成了IOC容器的初始化工作。这些BeanDefinition信息已经可以使用,并可以被检索,IOC容器的作用就是对这些注册的Bean定义信息进行处理和维护。

      这些注册的Bean定义信息是IOC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入

总结

通过上面的源码解析,可以得到IOC容器初始化的基本步骤:

在这里插入图片描述

初始化的入口在容器实现中的 refresh()调用来完成

对 bean 定义载入 IOC 容器使用的方法是 loadBeanDefinition,其中的大致过程如下:

  • 通过 ResourceLoader 来完成资源文件位置的定位,DefaultResourceLoader 是默认的实现,同时上下文本身就给出了 ResourceLoader 的实现,可以从类路径,文件系统, URL 等方式来定为资源位置。如果是 XmlBeanFactory作为 IOC 容器,那么需要为它指定 bean 定义的资源,也就是说 bean 定义文件时通过抽象成 Resource 来被 IOC 容器处理的

  • 通过 BeanDefinitionReader来完成定义信息的解析和 Bean 信息的注册, 往往使用的是XmlBeanDefinitionReader 来解析 bean 的 xml 定义文件 - 实际的处理过程是委托给 BeanDefinitionParserDelegate 来完成的,从而得到 bean 的定义信息,这些信息在 Spring 中使用 BeanDefinition 对象来表示 - 这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition 这些相关的方法 - 他们都是为处理 BeanDefinitin 服务的

  • 容器解析得到 BeanDefinition 以后,需要把它在 IOC 容器中注册,这由 IOC 实现 BeanDefinitionRegistry 接口来实现。注册过程就是在 IOC 容器内部维护的一个HashMap 来保存得到的 BeanDefinition 的过程。这个 HashMap 是 IoC 容器持有 bean 信息的场所,以后对 bean 的操作都是围绕这个HashMap 来实现的.

然后我们就可以通过 BeanFactory 和 ApplicationContext 来享受到 Spring IOC 的服务了,在使用 IOC 容器的时候,我们注意到除了少量粘合代码,绝大多数以正确 IoC 风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。 Spring 本身提供了对声明式载入 web 应用程序用法的应用程序上下文,并将其存储在ServletContext 中的框架实现。

  • 9
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值