SprinBoot2 | Spring IOC 源码学习笔记

概述

Spring IOC 过程实质是通过SpringBoot提供的注解,将需要注入的bean信息存入BeanDefinition中(包含类路径、类名、类的范围(单例,多例)、类属性等信息)并注册到DefaultListableBeanFactory中(实际存入beanDefinitionMap,mergedBeanDefinitions中)。

SprinBoot 版本:2.2.7.RELEASE

入口

IOC 主要发生在 refresh 的 invokeBeanFactoryPostProcessors阶段

@Override
	public void refresh() throws BeansException, IllegalStateException {
     
		synchronized (this.startupShutdownMonitor) {
     
			prepareRefresh();
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			prepareBeanFactory(beanFactory);
			try {
     
				postProcessBeanFactory(beanFactory);
				invokeBeanFactoryPostProcessors(beanFactory);
				registerBeanPostProcessors(beanFactory);
				initMessageSource();
				initApplicationEventMulticaster();
				onRefresh();
				registerListeners();
				finishBeanFactoryInitialization(beanFactory);
				finishRefresh();
			}
	}

invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
     
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
     
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
     
			// 省略代码
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			//省略代码
			}

invokeBeanDefinitionRegistryPostProcessors

private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
     

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
     
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}

主要调用ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(registry)进入processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法。

processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
     
// 省略代码
// 初始时,candidates 包含启动类(在准备上下文阶段被载入)
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
     
		// 解析配置类
			parser.parse(candidates);
			parser.validate();
         
			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
     
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			// 读取configClasses 将配置类中 @Import注入的bean,@Bean 注入的bean
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
     
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
     
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
     
					if (!oldCandidateNames.contains(candidateName)) {
     
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
     
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());
// 省略代码
}

这里主要关注 parser.parse(candidates); this.reader.loadBeanDefinitions(configClasses);这两个方法。
下面对pase和loadBeanDefinitions做为两个步骤讲解。

解析

步骤1:

1.1 parse

public void parse(Set<BeanDefinitionHolder> configCandidates) {
     
		for (BeanDefinitionHolder holder : configCandidates) {
     
			BeanDefinition bd = holder.getBeanDefinition();
			try {
     
				if (bd instanceof AnnotatedBeanDefinition) {
     
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
     
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
     
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
     
				throw ex;
			}
			catch (Throwable ex) {
     
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
// 处理@Import 注入实现DeferredImportSelector接口的bean
		this.deferredImportSelectorHandler.process();
	}

调用parse解析bean,this.deferredImportSelectorHandler.process (涉及@Import注解。处理导入bean实现DeferredImportSelector接口)

1.2 processConfigurationClass

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
     
// 条件注解扫描
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
     
			return;
		}
    // 省略代码
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
     
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
		this.configurationClasses.put(configClass, configClass);
	}

步骤:

  1. 对bean条件拦截,是否跳过注册。
  2. doProcessConfigurationClass:处理bean的注解。
  3. 将configClass(包含@Import @Bean 等注入的bean信息)存入configurationClasses中,在第步骤2中完成注册。

1.3 doProcessConfigurationClass (核心解析代码)

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
     
     // 类是否包含Compone注解,有则处理内部类
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
     
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 处理 @PropertySource 注解
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
     
			if (this.environment instanceof ConfigurableEnvironment) {
     
				processPropertySource(propertySource);
			}
			else {
     
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 处理 @ComponentScan 注解
		// 获取ComponeScan 信息
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
     
			for (AnnotationAttributes componentScan : componentScans) {
     
			// 通过componentScanParser 扫描包含@Component注解的类
			// 扫描路径为 CompoentScans 设置的path,若不存在,则为当前类(启动类)所在目录
			// 扫描后将类信息封装为 RootBeanDefinition 注册到工厂中。
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
     
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
     
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
     
			//递归调用parse方法解析类		
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		处理@Import 注解
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// 处理 @ImportResource 并将注入的资源信息 加入到 configClass
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
     
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
     
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// 处理 @Bean 注解,并将注入的方法信息 加入到 configClass
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
     
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
     
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
     
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

此方法依次对 Component的内部类、@PropertySource、 @ComponentScan、@Import、@Bean分别做了不同的处理。其中@ComponentScan将扫描到包含@Component注解的类直接注册到Spring工厂中;@Import、@Bean收集的类信息存入configClass中。
处理ComponentScan注解部分,componentScanParser是如何扫描注册bean的,有兴趣可以看看。

1.4 processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
     

		if (importCandidates.isEmpty()) {
     
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
     
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
     
			this.importStack.push(configClass);
			try {
     
			// 遍历@Import注入的bean
				for (SourceClass candidate : importCandidates) {
     
				// 注入的类实现 ImportSelector 
					if (candidate.isAssignable(ImportSelector.class)) {
     
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();
						if (selectorFilter != null) {
     
							exclusionFilter = exclusionFilter.or(selectorFilter);
						}
						// 如果类实现DeferredImportSelector,则将类信息存入deferredImportSelectorHandler
						if (selector instanceof DeferredImportSelector) {
     
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						// 如果只实现了ImportSelector接口,将类处理为SourceClass,再递归调用processImorts方法。
						else {
     
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
							processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
						}
					}
					// 如果类实现了ImportBeanDefinitionRegistrar,则将类信息存入configClass中。(在步骤2中处理)
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
     
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
     
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						// 注意这里asConfigClass方法,生成的ConfigurationClass的importedBy不为null。(在步骤2中解析)。
						processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
     
				throw ex;
			}
			catch (Throwable ex) {
     
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
     
				this.importStack.pop();
			}
		}
	}

通过processImports 我们可以看出 @Import 注解的作用

  1. 导入类实现DeferredImportSelector接口。(在1.1 部分,调用类实现方法,并对返回类信息批量延迟导入。延迟导入作用:在1.2部分我们可以看到,条件拦截(条件注解)先对注册的类进行了判断,能满足某些类需要其他类存在,或者不存在,才导入的需求)
  2. 导入类实现ImportSelector接口。(调用类实现方法,并对返回类信息批量导入)
  3. 导入类实现ImportBeanDefinitionRegistrar接口。(调用实现方法,直接向工厂注册类,常用扩展接口,例如:mybatis 的@MapperScan也使用到此接口 )
  4. 导入普通类(对 1、2部分的代码最终还是会执行4)

步骤2

2.1 loadBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
     
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
     
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

处理步骤1,解析过程暂存的ConfigurationClass。

2.2 loadBeanDefinitionsForConfigurationClass

private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
     

		if (trackedConditionEvaluator.shouldSkip(configClass)) {
     
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
     
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}
  // configClss 是否是导入的bean,在1.4部分提及 
		if (configClass.isImported()) {
     
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
     
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

这部分是对步骤1的补充,调用(registerBeanDefinitionForImportedConfigurationClass、loadBeanDefinitionsForBeanMethod、loadBeanDefinitionsFromImportedResources、loadBeanDefinitionsFromRegistrars)方法将类信息存入BeanDefinition的实现类中并注册到工厂中。

@SpringBootApplication

上面介绍了ioc过程,ioc是从启动类开始的,那么@SpringBootApplication有什么作用呢?

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
      @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
     
// 省略代码
}

这里包含了CompoentScan 注解(默认扫描启动类所在的目录)、@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
     
// 省略代码
}

@EnableAutoConfiguration包含@Import注解导入了AutoConfigurationImportSelector

AutoConfigurationImportSelector

ublic class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
     
 // 省略代码
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
     
		if (!isEnabled(annotationMetadata)) {
     
			return NO_IMPORTS;
		}
		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
				.loadMetadata(this.beanClassLoader);
		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
				annotationMetadata);
		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
	}

      protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
     
		if (!isEnabled(annotationMetadata)) {
     
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

   protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
     
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}
   protected Class<?> getSpringFactoriesLoaderFactoryClass() {
     
		return EnableAutoConfiguration.class;
	}

AutoConfigurationImportSelector 实现 DeferredImportSelector ,selectImports方法返回的类信息是通过
SpringFactoriesLoader.loadFactoryNames方法读取META-INF/spring.factories 中EnableAutoConfiguration.class 配置自动注入的类信息。由于starter插件中需要默认注入一些类(使用到了条件注解,允许用户自定义或注入类需要其他类存在),所以AutoConfigurationImportSelector 实现 DeferredImportSelector 来延迟导入。

你可能感兴趣的:(SpringBoot,spring,boot)