IOC容器初始化-二

/ Spring / 没有评论 / 18浏览

上一篇走了一遍源码,知道了IOC容器大概的一个初始化过程。

spring ioc的一个过程是:

1、定位

ClassPathXmlApplicationContext的构造方法,输入资源路径,

public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      //关键代码
     /**
      * 设置资源路径
      */
     setConfigLocations(configLocations);
}

然后由AbstractBeanDefinitionReaderResourceLoader对configLocations进行转化为Resource

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException 

2、加载

跟踪代码到XmlBeanDefinitionReader,它的loadBeanDefinitions才是加载的真正入口

public int loadBeanDefinitions(EncodedResource encodedResource)throws BeanDefinitionStoreException {
	//关键代码
    return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource){
	//关键代码
    Document doc = doLoadDocument(inputSource, resource);
	return registerBeanDefinitions(doc, resource);
}

2.1、加载Dom对象

由DefaultDocumentLoader对Resource进行解析,生成Dom对象

private DocumentLoader documentLoader = new DefaultDocumentLoader();
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

2.2、DefaultBeanDefinitionDocumentReader对dom对象进行更加深入的解析

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();//获取element对象
   doRegisterBeanDefinitions(root);//根据element进行更加深入的解析
}
protected void doRegisterBeanDefinitions(Element root) {
   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);
         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;
}

doRegisterBeanDefinitions,这个方法,做了一下几件事:

a)生成BeanDefinitionParserDelegate,这个接口后续对Element进行bean的解析

b) xml加载解析的前置操作

c)委派BeanDefinitionParserDelegate进行解析任务

d)xml加载解析的后置操作

进到parseBeanDefinitions方法,对Element进行循环解析parseDefaultElement(假设是默认配置),

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)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

拿bean的解析来说,processBeanDefinition(ele, delegate)

/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
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));
   }
}

由上面的代码可以知道:

a)由BeanDefinitionParserDelegate对element进行解析,生成BeanDefinitionHolder(它是对配置文件的描述,如beanname,class,id等等)

b)由BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());进行注册,从而引申到注册

3、注册

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//由BeanDefinitionRegistry维护BeanDefinition

   // Register aliases for bean name, if any.
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

由上面的代码可以得知:BeanDefinition实际是由BeanDefinitionRegistry.registerBeanDefinition(委托给DefaultListableBeanFactory.registerBeanDefinition)进行注册的,从下面这个方法也可以得到验证:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

  //关键代码
  this.beanDefinitionMap.put(beanName, beanDefinition);
}

由上面的代码可以知道,IOC注册最后由Map进行维护

/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);