Spring IOC 源码阅读--读取BeanDefinition

59 阅读3分钟

bg:25届毕业生,目前在实习,记录一下学习成长过程中的感悟。

个人心得:如果没有源码阅读经验的新手在刚接触源码的时候很容易晕头转向。网上关于Spring源码的资料和视频很多,但是都很杂,而且每个人的痛点都不一样,就需要从各个资料中去整合。这个过程。。。非常的痛苦。下面就具体说明一下我的学习方式和个人理解,理解有误的地方欢迎指正。

Spring IOC流程

根据流程图可以看IOC容器创建Bean对象可以大致分为三步:

  1. 读取BeanDefinition(Bean定义信息)
  2. 实例化(创建Bean)
  3. 初始化(填充Bean)

image.png

读取BeanDefinition

Spring两大容器BeanFactory和ApplicationContext我就不介绍了,这里详细介绍一下ApplicationContext的实现子类AnnotationConfigApplicationContext(注解)以及对比一下ClassPathXmlApplicationContext(XML)。

两个类的构造函数都调用了refresh()方法,该方法继承于AbstractApplicationContext,也是容器管理Bean的主要方法。Spring要想管理Bean,首先要先new一个BeanFactory容器,依托这个容器去管理。这两个类第一个不同的地方就在于容器创建时间,AnnotationConfigApplicationContext在调用this()无参构造的同时会调用父类GenericApplicationContext的无参构造new一个DefaultListableBeanFactory。而ClassPathXmlApplicationContext发生在refresh()中的obtainFreshBeanFactory()方法。在容器准备就绪后就可以开始读取Beandefinition了。

image.png

image.png 第二个不同也来了,AnnotationConfigApplicationContext使用scan()方法读取,而ClassPathXmlApplicationContext同样发生在obtainFreshBeanFactory()方法里的 loadBeanDefinitions()方法中。接下来具体讲一下scan()方法。

scan()方法通过一次次套娃的重写和调用,定位到一个重要方法doScan()。在该方法中有一个findCandidateComponents()方法会去读取候选的BeanDefinition,也就是加了@Components注解的Bean。该方法首先会通过读取Resource的方式将指定包下的class文件读取出来,再通过isCandidateComponent()方法判断是否添加了@Components注解,在isCandidateComponent()方法中可以看到一个includeFilters,而这个list里Components的值哪里来的呢?这就要回到AnnotationConfigApplicationContext的构造函数了,在构造函数里new了一个ClassPathBeanDefinitionScanner。顺着这个scanner的构造函数能找到registerDefaultFilters()方法,在这个方法里将Components注册到了includeFilters。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
       Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
       for (BeanDefinition candidate : candidates) {
          ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
          candidate.setScope(scopeMetadata.getScopeName());
          String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
          if (candidate instanceof AbstractBeanDefinition) {
             postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
          }
          if (candidate instanceof AnnotatedBeanDefinition) {
             AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
          }
          if (checkCandidate(beanName, candidate)) {
             BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
             definitionHolder =
                   AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
             beanDefinitions.add(definitionHolder);
             registerBeanDefinition(definitionHolder, this.registry);
          }
       }
    }
    return beanDefinitions;
}
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
    for (TypeFilter tf : this.excludeFilters) {
       if (tf.match(metadataReader, getMetadataReaderFactory())) {
          return false;
       }
    }
    for (TypeFilter tf : this.includeFilters) {
       if (tf.match(metadataReader, getMetadataReaderFactory())) {
          return isConditionMatch(metadataReader);
       }
    }
    return false;
}

有了候选BeanDefinition之后,通过对这些BeanDefinition进行扩展处理、封装等操作,开始通过registerBeanDefinition()方法注册。同样的,通过一次次的套娃重写和调用,会来到DefaultListableBeanFactory的registerBeanDefinition(),该方法会把BeanDefinition注册到beanDefinitionMap中。至此读取BeanDefinition工作告一段落。

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<>(this.beanDefinitionNames.size() + 1);
           updatedDefinitions.addAll(this.beanDefinitionNames);
           updatedDefinitions.add(beanName);
		this.beanDefinitionNames = updatedDefinitions;
		removeManualSingletonName(beanName);
	}
}
else {
	// Still in startup registration phase
	this.beanDefinitionMap.put(beanName, beanDefinition);
	this.beanDefinitionNames.add(beanName);
	removeManualSingletonName(beanName);
}
	this.frozenBeanDefinitionNames = null;}

剩下的后续慢慢写。。。