pringboot2.0.6啓動解析(十)刷新應用程序上下文-IoC容器的初始化

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      ......//省略   
      // 調用 beanFactory 後置處理器 
      invokeBeanFactoryPostProcessors(beanFactory);
      ......//省略  
   }
}

invokeBeanFactoryPostProcessors

該方法中完成IoC容器的初始化。具體步驟以下java

  1. Resource定位
    • 咱們知道在SpringBoot中包掃描默認是從主類所在的包開始掃描的,在準備應用上下文時,即在prepareContext()方法中會先將主類解析成BeanDefinition,而後在refresh方法中調用invokeBeanFactoryPostProcessors方法,其解析主類的BeanDefinition獲取basePackage的路徑,完成掃描路徑的定位。其次SpringBoot的starter是經過SPI擴展機制實現的自動裝配,SpringBoot的自動裝配一樣也是在invokeBeanFactoryPostProcessors方法中觸發實現的。還另外在SpringBoot中還有不少的@EnableXXX註解,查看得知其底層是@Import註解,在invokeBeanFactoryPostProcessors方法中也實現了對該註解指定的配置類的定位加載。
    • 常規的在SpringBoot中有四種實現定位
      1. 主類所在包的
      2. @ComponentScan指定掃描目錄
      3. SPI擴展機制實現的自動裝配(好比各類starter)
      4. @Import註解指定的類。(對於很是規的不說了)
  2. BeanDefinition的載入
    • 找到了掃描包的位置,定位後緊接着要作的就是將BeanDefinition的分別載入。所謂的載入就是經過上面的定位獲得的basePackage的路徑拼接成「classpath*:org/springframework/boot/demo/**/*.class」這樣的形式,PathMatchingResourcePatternResolver類會將該路徑下全部的 .class 文件都加載進來,而後遍歷判斷是否有@Component註解,若是有的話其就是咱們要裝載的BeanDefinition。
    • 注意@Configuration,@Controller,@Service等註解底層都是@Component註解,只不過包裝了一層罷了
  3. 註冊BeanDefinition
    • 這個過程是經過調用前文中提到的BeanDefinitionRegister接口的實現來完成。其把載入過程當中解析獲得的BeanDefinition向IoC容器進行註冊,即在IoC容器中將BeanDefinition注入到一個ConcurrentHashMap中,IoC容器就是經過這個HashMap來持有這些BeanDefinition數據的。好比DefaultListableBeanFactory 中的beanDefinitionMap屬性。
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方法spring

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}
private static void invokeBeanDefinitionRegistryPostProcessors(
         Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { 
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}

invokeBeanFactoryPostProcessors看着挺長其實裏面的內容仍是比較好理解的。其主要就是對BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的bean進行處理。springboot

  1. BeanDefinitionRegistryPostProcessor
    • 首先判斷傳入的beanFactory是否是BeanDefinitionRegistry的實例。
    •  beanFactory是BeanDefinitionRegistry,咱們開始處理BeanFactoryPostProcessor,即遍歷每個對象,驗證是否是BeanDefinitionRegistryPostProcessor(BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子接口)的實例。是將其強制類型轉換,而後執行BeanDefinitionRegistryPostProcessor的生命週期方法postProcessBeanDefinitionRegistry,而且將這個BeanFactoryPostProcessor放入到registryPostProcessors集合中。不是則直接放入到regularPostProcessors集合中。它們都放入集合中以後咱們就能夠處理集合中的屬於BeanDefinitionRegistryPostProcessor類型的Bean了。app

      獲取BeanDefinitionRegistryPostProcessor類型的Bean的集合,處理這些bean,即遍歷每個對象,驗證是否是PriorityOrdered類型的,是放入currentRegistryProcessors集合中並把bean名稱放入processedBeans(已經處理過的Bean的集合)集合中,防止重複執行,而後排序,把該集合加入registryProcessors集合中。在invokeBeanDefinitionRegistryPostProcessors方法中,處理currentRegistryProcessors集合,即遍歷每個對象,執行BeanDefinitionRegistryPostProcessor的生命週期方法postProcessBeanDefinitionRegistry。在用用一樣的方法處理rdered類型的Bean。在用一樣的方法處理剩餘的bean直到全部的bean都處理完。而後在執行BeanFactoryPostProcessor的生命週期方法postProcessBeanFactory處理 registryProcessors 和 regularPostProcessors兩個集合。ide

    • beanFactory不是BeanDefinitionRegistry咱們則直接BeanFactoryPostProcessor的生命週期方法postProcessBeanFactory將BeanFactoryPostProcessor處理掉。post

  2. BeanFactoryPostProcessor

        其處理的方式與BeanDefinitionRegistryPostProcessor相同,即先處理完PriorityOrdered,再處理Ordered,最後統一處理普通的,這裏要注意的是,由於BeanDefinitionRegistryPostProcessor也是BeanFactoryPostProcessor,因此在這裏須要過濾掉不處理了。ui

下面咱們來分析一些其核心方法invokeBeanDefinitionRegistryPostProcessors看看他是如何實現的this

private static void invokeBeanDefinitionRegistryPostProcessors(
         Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { 
    for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanDefinitionRegistry(registry);
    }
}

在PostProcessorRegistrationDelegate類的invokeBeanDefinitionRegistryPostProcessors方法進入ConfigurationClassPostProcessor類的postProcessBeanDefinitionRegistry方法lua

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    ...
    processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    ...
    do {
        parser.parse(candidates);
        parser.validate();
        ...
    }
    ...
}

在processConfigBeanDefinitions中進入ConfigurationClassParser類的parse方法spa

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<>();
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            // 在SpringBoot項目中,bd其實就是前面主類封裝成的 AnnotatedGenericBeanDefinition(AnnotatedBeanDefinition接口的實現類)
            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);
        }
    }
    // 加載默認的配置(這裏就是自動裝配的入口了)
    processDeferredImportSelectors();
}

咱們已經在前面文章《springboot2.0.6啓動解析(八)準備上下文》中詳細介紹了SpringBoot項目的主類是如何一步步的封裝成AnnotatedGenericBeanDefinition,並註冊進IoC容器的beanDefinitionMap中的。也在前面文章《springboot2.0.6啓動解析(一)自動配置》中對processDeferredImportSelectors進行了詳細講解。

跟進parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName())方法,進入ConfigurationClassParser類的processConfigurationClass方法

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(),	ConfigurationPhase.PARSE_CONFIGURATION)) {
	return;
	}
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			return;
		} else {
			// Explicit bean definition found, probably replacing an import.
			// Let's remove the old one and go with the new one.
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}
	// 遞歸處理配置類及其弗雷層次結構
	SourceClass sourceClass = asSourceClass(configClass);
	do {
	    // 遞歸處理Bean,直到頂層父類
		sourceClass = doProcessConfigurationClass(configClass, sourceClass);
	}
	while (sourceClass != null);
	this.configurationClasses.put(configClass, configClass);
}

進入asSourceClass方法 

private SourceClass asSourceClass(ConfigurationClass configurationClass) throws IOException {
	AnnotationMetadata metadata = configurationClass.getMetadata();
	if (metadata instanceof StandardAnnotationMetadata) {
		return asSourceClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
	}
	return asSourceClass(metadata.getClassName());
}

進入doProcessConfigurationClass方法

/* SpringBoot的包掃描的入口方法(重點)*/
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
		throws IOException {
	// Recursively process any member (nested) classes first
    //遞歸處理內部類,(主類通常沒有內部類)
	processMemberClasses(configClass, sourceClass);
	// Process any @PropertySource annotations
    // ① 處理 @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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}
	// Process any @ComponentScan annotations
    // ② 根據 @ComponentScan 註解,掃描項目中的Bean(SpringBoot 主類上可能有該註解)
	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) {
			// The config class is annotated with @ComponentScan -> perform the scan immediately
            // ③ 執行掃描,(今後處能夠了解到爲何從主類所在的包掃描開始掃描)
			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();
				}
                // 判斷是不是ConfigurationClass(有configuration、component兩個註解),是則遞歸查找該類相關聯的配置類(@Configuration中的@Bean定義的bean。或者在有@Component註解的類上繼續存在@Import註解等都是相關的配置類)。
				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    //眼熟把,眼熟就對了這進行了對貴調用(由於當Spring掃描到須要加載的類會進一步判斷每個類是否知足是@Component、@Configuration註解的類,知足則會遞歸調用parse()方法,查找其相關的類即其外層的if判斷語句)
					parse(bdCand.getBeanClassName(), holder.getBeanName());
				}
			}
		}
	}
	// Process any @Import annotations
	// ④ 遞歸處理@Import註解(SpringBoot中的各類@Enable***註解底層基本都是封裝的@Import)
	processImports(configClass, sourceClass, getImports(sourceClass), true);

	// Process any @ImportResource annotations
	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);
		}
	}
	// Process individual @Bean methods
	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;
}

① 獲取主類上的@PropertySource註解進行解析並將該註解指定的properties配置文件中的值存儲到Spring的 Environment 中,Environment 接口提供方法去讀取配置文件中的值,參數是 properties 文件中定義的key值。
② 解析主類上的@ComponentScan註解,獲取註解值,掃描解析詳情請看③中分析。


③  遍歷處理componentScans,解析註解並進行包掃描

④ 解析主類上的@Import註解,並加載該註解指定的配置類。

1. 定位掃描路徑進行 IoC 初始化

關鍵具體處理在ComponentScanAnnotationParser類的parse方法,咱們進入該方法

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
			componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
    //設置BeanNameGenerator
	Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
	boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
	scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
			BeanUtils.instantiateClass(generatorClass));
    //設置ScopedProxyMode
	ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
	if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
		scanner.setScopedProxyMode(scopedProxyMode);
	} else {
		Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
		scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
	}
    //設置ResourcePattern
	scanner.setResourcePattern(componentScan.getString("resourcePattern"));
    //設置IncludeFilter
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addIncludeFilter(typeFilter);
		}
	}
    //設置ExcludeFilter
	for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
		for (TypeFilter typeFilter : typeFiltersFor(filter)) {
			scanner.addExcludeFilter(typeFilter);
		}
	}
    //設置LazyInit
	boolean lazyInit = componentScan.getBoolean("lazyInit");
	if (lazyInit) {
		scanner.getBeanDefinitionDefaults().setLazyInit(true);
	}

	Set<String> basePackages = new LinkedHashSet<>();
    //獲取@ComponentScan註解設置的掃描路徑集合
	String[] basePackagesArray = componentScan.getStringArray("basePackages");
    //遍歷處理把掃描路徑添加到basePackages集合中
	for (String pkg : basePackagesArray) {
		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		Collections.addAll(basePackages, tokenized);
	}
     // 根據 clazz 獲取掃描路徑(SpringBoot項目則參數爲主類的全路徑名)
	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
		basePackages.add(ClassUtils.getPackageName(clazz));
	}
     // 當basePackages爲控值時,根據 declaringClass 獲取掃描路徑(SpringBoot項目則參數爲主類的全路徑名)添加到basePackages集合中
	if (basePackages.isEmpty()) {
		basePackages.add(ClassUtils.getPackageName(declaringClass));
	}
    //設置AbstractTypeHierarchyTraversingFilter類型的ExcludeFilter
	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
		@Override
		protected boolean matchClassName(String className) {
			return declaringClass.equals(className);
		}
	});
    // 根據basePackages掃描類
	return scanner.doScan(StringUtils.toStringArray(basePackages));
}

到這裏咱們就找到了裝配的掃描路徑,即完成了Resource定位。通過分析咱們獲得在主類上有@ComponentScan註解的話掃描路徑爲其指定的路徑。沒有的化話就是主類所在的包。

完成了掃描路徑的定位,下面讓進入ClassPathBeanDefinitionScanner類的都Scan方法看看其是如何進行掃描的

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) {
            // 從指定的包中掃描須要裝載的Bean
			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);
                //將該 Bean 註冊進 IoC容器(beanDefinitionMap)
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

分析該類得知findCandidateComponents方法從basePackage中掃描類並解析成BeanDefinition,拿到全部符合條件的類後registerBeanDefinition方法將該類註冊進IoC容器。也就是說在方法doScan中完成了IoC容器初始化過程的第載入和註冊,即BeanDefinition的載入,和BeanDefinition的註冊

進入ClassPathScanningCandidateComponentProvider類的findCandidateComponents方法

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
   if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
      return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
   }
   else {
      return scanCandidateComponents(basePackage);
   }
}

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
	Set<BeanDefinition> candidates = new LinkedHashSet<>();
	try {
        //拼接掃描路徑,好比:classpath*:com/xds/test/demo/controller/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
        //從 packageSearchPath 路徑中掃描全部的類
		Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                    //判斷metadataReader類是否是 被@Component 註解標註且不是須要排除掉的類
					if (isCandidateComponent(metadataReader)) {
                        //將該類封裝成 ScannedGenericBeanDefinition(BeanDefinition接口的實現類)
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}else {
							if (debugEnabled) {
								logger.debug("Ignored because not a concrete top-level class: " + resource);
							}
						}
					}else {
						if (traceEnabled) {
							logger.trace("Ignored because not matching any filter: " + resource);
						}
					}
				}catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}else {
				if (traceEnabled) {
					logger.trace("Ignored because not readable: " + resource);
				}
			}
		}
	}catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

在scanCandidateComponents方法中先將basePackage拼接成classpath類型的掃描路徑packageSearchPath。再調用getResources(packageSearchPath)方法,掃描到了該路徑下的全部的類。而後遍歷掃描獲取到的類的集合,判斷其是否是 被@Component 註解標註且不是須要排除掉的類。知足添加則將掃描到的類,解析成ScannedGenericBeanDefinition,該類是BeanDefinition接口的實現類。到這裏IoC容器的BeanDefinition載入就結束了。換句話scanCandidateComponents方法完成了BeanDefinition載入。

下面咱們進入registerBeanDefinition方法看看其實如何完成BeanDefinition註冊的

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

查看registerBeanDefinition方法。BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry)這段代碼很眼熟,咱們在在前面介紹prepareContext()方法時,已經詳細介紹了主類的BeanDefinition是怎麼一步一步的註冊進DefaultListableBeanFactory的beanDefinitionMap中的。而完成了BeanDefinition的註冊,就完成了IoC容器的初始化過程。此時,在使用的IoC容器DefaultListableFactory中已經創建了整個Bean的配置信息,而這些BeanDefinition已經能夠被容器使用了。由於它們都在BeanbefinitionMap這個集合裏被檢索和使用。容器的做用就是對這些信息進行處理和維護。固然這些信息是容器創建依賴反轉的基礎。

2. @Import註解解析過程

前面說到過SpringBoot中的各類@EnableXXX註解,很大一部分都是對@Import的二次封裝(目的其實就是爲了解耦)。

首先咱們看看getImports方法,看看如何遞歸遍歷解析@Import,獲取其引用的類

private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	Set<SourceClass> imports = new LinkedHashSet<>();
	Set<SourceClass> visited = new LinkedHashSet<>();
	collectImports(sourceClass, imports, visited);
	return imports;
}

 

因爲是@EnableAutoConfiguration註解中引用了@AutoConfigurationPackage註解而@AutoConfigurationPackage註解有使用@Import註解指定了「AutoConfigurationPackages.Registrar.class」類,而且@EnableAutoConfiguration自己使用@Import註解指定了「AutoConfigurationImportSelector.class」類。因此遞歸處理獲取@import引用獲取到的imports集合有兩個值。

接下來讓咱們來看看ConfigurationClassParser類的doProcessConfigurationClass方法的中的processImports(configClass, sourceClass, getImports(sourceClass), true)方法,注意中configClass和sourceClass參數都是主類相對應的值

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, 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的value能夠指定三種類型:帶有@Configuration的類、ImportSelector實現、ImportBeanDefinitionRegistrar實現
			for (SourceClass candidate : importCandidates) {
                // 判斷candidate是否是ImportSelector.class類型
				if (candidate.isAssignable(ImportSelector.class)) {
					// Candidate class is an ImportSelector -> delegate to it to determine imports
					Class<?> candidateClass = candidate.loadClass();
                    // 獲取ImportSelector對象
					ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
					ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
                    // 當前類是DeferredImportSelector 的實現,則加入到deferredImportSelectors,到全部配置類都解析後處理
					if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
						this.deferredImportSelectors.add(
								new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
					}else {
                        // 不是則調用processImports 進行處理
						String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
						Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
						processImports(configClass, currentSourceClass, importSourceClasses, false);
					}
				}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 =
							BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
					ParserStrategyUtils.invokeAwareMethods(
							registrar, this.environment, this.resourceLoader, this.registry);
					configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
				}else {// 加入到importStack後調用processConfigurationClass 進行處理
					// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
					// process it as an @Configuration class
					this.importStack.registerImport(
							currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
					processConfigurationClass(candidate.asConfigClass(configClass));
				}
			}
		}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();
		}
	}
}

 該方法解析@Import註解,並加載該註解指定的配置類,有好多註解都是一層一層封裝的,好比@EnableXXX就是對@Import註解的二次封裝。

自動配置AutoConfigurationImportSelector類的selectImports方法在處啓用。

相關文章
相關標籤/搜索