Spring Ioc容器阅读笔记

Ioc容器初始化流程<
  • Ioc初始化的入口就是refresh方法(可以参看FileSystemXmlApplicationContext类)

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException {


    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
    refresh();
    }
    }

该refresh方法标志着Ioc容器正式启动。其启动可以分为如下三个步骤:

  1. Resource定位(由ResourceLoader模块负责)
  2. BeanDefinition载入,解析(由BeanDefinitionReader模块负责)。将定义好的Bean载入,解析成Ioc容器内部的数据结构(BeanDefinition)。通过这个BeanDefinition,Ioc容器实现对Bean的管理。
  3. BeanDefinition注册。该过程通过调用BeanDefinitionRegistry接口实现完成。其本质是将解析得到的BeanDefinition放入Ioc容器的HashMap中。
    //DefaultListableBeanFactory类中
    // Map of bean definition objects, keyed by bean name
        private final Map <String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap <String,BeanDefinition>();
PS:另外这里强调下BeanDefinition的注册与Bean依赖的注入的区别:
BeanDefinition的注册仅仅负责将BeanDefinition放入HashMap中即完成了注册。依赖的注入不是在Ioc容器启动的时候完成的。而是在getBean()实例的时候才
触发依赖的注入。这两个是独立的过程。
  • BeanDefinition Resource定位
查看类AbstractBeanDefinitionReader:
    public int loadBeanDefinitions(String location, Set
    <Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
        //...
        }


        if (resourceLoader instanceof ResourcePatternResolver) {
        // Resource pattern matching available.
        try {
        Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
        int loadCount = loadBeanDefinitions(resources);
        if (actualResources != null) {
        ...
        }
        }


        return loadCount;
        }
        catch (IOException ex) {
        //...
        }
        }
        else {
        //....
        }
        }

关键根据location来定位Resource的地方来了,请看:
    public Resource[] getResources(String locationPattern) throws IOException {
    Assert.notNull(locationPattern, "Location pattern must not be null");
    if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
    // a class path resource (multiple resources for same name possible)
    if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
    // a class path resource pattern
    return findPathMatchingResources(locationPattern);
    }
    else {
    // all class path resources with the given name
    return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
    }
    }
    else {
    // Only look for a pattern after a prefix here
    // (to not get fooled by a pattern symbol in a strange prefix).
    int prefixEnd = locationPattern.indexOf(":") + 1;
    if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
    // a file pattern
    return findPathMatchingResources(locationPattern);
    }
    else {
    // a single resource with the given name
    return new Resource[] {getResourceLoader().getResource(locationPattern)};
    }
    }
    }

至此,从上面classpath*:路径和和:开头的路径下的Resource都找到了。
  • BeanDefinition 载入和解析
我们重新回到refresh方法来看载入:
    public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();


    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();


    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);


    try {
    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);


    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);


    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);


    // Initialize message source for this context.
    initMessageSource();


    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();


    // Initialize other special beans in specific context subclasses.
    onRefresh();


    // Check for listener beans and register them.
    registerListeners();


    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);


    // Last step: publish corresponding event.
    finishRefresh();
    }


    catch (BeansException ex) {
    // Destroy already created singletons to avoid dangling resources.
    destroyBeans();


    // Reset 'active' flag.
    cancelRefresh(ex);


    // Propagate exception to caller.
    throw ex;
    }
    }
    }
上面整个refresh方法就像计算机系统重启一样。我们看简单版本的载入。从XmlBeanFactory的
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
      super(parentBeanFactory);
      this.reader.loadBeanDefinitions(resource);
   }
进入到XmlBeanDefinitionReader的
    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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
          if (currentResources == null) {
             currentResources = new HashSet<EncodedResource>(4);
             this.resourcesCurrentlyBeingLoaded.set(currentResources);
          }
          if (!currentResources.add(encodedResource)) {
             throw new BeanDefinitionStoreException(
                   "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
          }
          try {
             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) {
                //....
          }
       }
再进入到
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
         throws BeanDefinitionStoreException {
      try {
         int validationMode = getValidationModeForResource(resource);
         Document doc = this.documentLoader.loadDocument(
               inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
         return registerBeanDefinitions(doc, resource);
      }
      catch (BeanDefinitionStoreException ex) {
         //..
      }
      }


      public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
              BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
              documentReader.setEnvironment(this.getEnvironment());
              int countBefore = getRegistry().getBeanDefinitionCount();
              documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
              return getRegistry().getBeanDefinitionCount() - countBefore;
        }
上面将Xml配置文件,读取到内存变成一个Xml Document,然后交给BeanDefinitionDocumentReader解析这个Document。
进入到DefaultBeanDefinitionDocumentReader类看
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);
      }
   }

至此,就开始进行一些标签(import,bean)的解析了。
  • BeanDefinition 注册
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值