public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ......//省略 // 調用 beanFactory 後置處理器 invokeBeanFactoryPostProcessors(beanFactory); ......//省略 } }
該方法中完成IoC容器的初始化。具體步驟以下java
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
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
其處理的方式與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註解,並加載該註解指定的配置類。
關鍵具體處理在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這個集合裏被檢索和使用。容器的做用就是對這些信息進行處理和維護。固然這些信息是容器創建依賴反轉的基礎。
前面說到過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方法在處啓用。