深入剖析Spring boot自動裝配原理二(Import)

前言

關於@Import註解的使用,在Spring原始碼中隨處可見,其作用大家基本也都知道,無非就是注入指定的Bean到Spring IOC容器管理,只能作用用於類上,其用法分三種:普通的類直接注入、實現了ImportSelector介面的類、實現了ImportBeanDefinitionRegistrar介面的類,那麼Spring具體是如何實現的?這三種方式又有何不同?一起跟進原始碼一探究竟,徹底瞭解Import的實現。

原始碼追蹤(Spring版本:

5。3。6-SNAPSHOT

眾所周知Spring需要先初始化上下文容器,Spring上下文容器針對不同的場景設計了較多型別,不過都大同小異,這裡拿其中的AnnotationConfigApplicationContext進行講解,如果需要進一步瞭解Spring的每一個容器或者Spring的更多原始碼細節,可關注我,我會在後面的章節中逐步揭開Spring原始碼迷霧。

您的認可是我前進的動力,如果您覺得可以請關注我並轉發文章,謝謝!!!

AnnotationConfigApplicationContext(AbstractApplicationContext)

public AnnotationConfigApplicationContext(Class<?>。。。 componentClasses) { // 註解配置上下文初始化 this(); // 將配置元件(AppConfig)註冊到AnnotationConfigApplicationContext上下文物件的beanFactory中(即將bean資訊放入beanDefinitionMap中) register(componentClasses); // 重新整理註冊到AnnotationConfigApplicationContext上下文物件的相關屬性 refresh();}@Override// AbstractApplicationContext公共方法public void refresh() throws BeansException, IllegalStateException { synchronized (this。startupShutdownMonitor) { StartupStep contextRefresh = this。applicationStartup。start(“spring。context。refresh”); // Prepare this context for refreshing。 prepareRefresh(); // 重新整理AnnotationConfigApplicationContext上下文物件的BeanFactory並返回BeanFactory物件 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); StartupStep beanPostProcess = this。applicationStartup。start(“spring。context。beans。post-process”); // 例項化並呼叫所有已註冊的BeanFactoryPostProcessor的Bean到Spring容器中。 invokeBeanFactoryPostProcessors(beanFactory); …… // 例項化所有BeanFactory中非延遲載入的Bean。 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event。 finishRefresh(); } ……}

PostProcessorRegistrationDelegate

public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) { …… // 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 currentRegistryProcessors = new ArrayList<>(); // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered。 // 獲取BeanDefinitionRegistryPostProcessor型別的bean名稱,注意這裡獲取到了名字為 // org。springframework。context。annotation。internalConfigurationAnnotationProcessor的bean // (這個bean不是直接存在的,在AnnotationConfigUtils類中可查到其對應的Ben為ConfigurationClassPostProcessor) String[] postProcessorNames = beanFactory。getBeanNamesForType(BeanDefinitionRegistryPostProcessor。class, true, false); for (String ppName : postProcessorNames) { if (beanFactory。isTypeMatch(ppName, PriorityOrdered。class)) { // beanFactory。getBean(ppName, BeanDefinitionRegistryPostProcessor。class)獲取到ConfigurationClassPostProcessor // 將ConfigurationClassPostProcessor新增到當前註冊Bean的處理物件集合 currentRegistryProcessors。add(beanFactory。getBean(ppName, BeanDefinitionRegistryPostProcessor。class)); processedBeans。add(ppName); } } // 將BeanDefinitionRegistryPostProcessor排序 sortPostProcessors(currentRegistryProcessors, beanFactory); // 將BeanDefinitionRegistryPostProcessor稍後註冊到BeanFactory registryProcessors。addAll(currentRegistryProcessors); // invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory。getApplicationStartup()); currentRegistryProcessors。clear(); ……}

透過呼叫PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors方法迴圈執行所有BeanDefinitionRegistryPostProcessor,將相關Bean注入BeanFacotry。這裡透過呼叫ConfigurationClassPostProcessor 處理所有@Configuration配置類,其透過核心方法processConfigBeanDefinitions來處理相關Bean的注入。

ConfigurationClassPostProcessor

@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 生成處理ID int factoryId = System。identityHashCode(beanFactory); // 判斷後置處理器在registriesPostProcessed和factoriesPostProcessed中有沒有被呼叫過 if (this。factoriesPostProcessed。contains(factoryId)) { throw new IllegalStateException( “postProcessBeanFactory already called on this post-processor against ” + beanFactory); } // 呼叫前儲存factoryId,防止被重複呼叫 this。factoriesPostProcessed。add(factoryId); if (!this。registriesPostProcessed。contains(factoryId)) { // 注入標有@configuration的Bean裡面需要注入的類(如:@Import註解) processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory); } enhanceConfigurationClasses(beanFactory); beanFactory。addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));}public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { // 需要處理的候選@configuration類 List configCandidates = new ArrayList<>(); // 獲取BeanFactory中注入的所有beanDefinitionNames String[] candidateNames = registry。getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry。getBeanDefinition(beanName); // 檢查當前Bean是否已當作配置類處理過 if (beanDef。getAttribute(ConfigurationClassUtils。CONFIGURATION_CLASS_ATTRIBUTE) != null) { if (logger。isDebugEnabled()) { logger。debug(“Bean definition has already been processed as a configuration class: ” + beanDef); } } // 檢查當前Bean是否是配置類,如果是則新增到configCandidates中,後面進行處理 else if (ConfigurationClassUtils。checkConfigurationClassCandidate(beanDef, this。metadataReaderFactory)) { configCandidates。add(new BeanDefinitionHolder(beanDef, beanName)); } } // Return immediately if no @Configuration classes were found if (configCandidates。isEmpty()) { return; } …… // 準備解析 @Configuration 標註的類,構建解析物件 ConfigurationClassParser parser = new ConfigurationClassParser( this。metadataReaderFactory, this。problemReporter, this。environment, this。resourceLoader, this。componentScanBeanNameGenerator, registry); // 配置Bean去重 Set candidates = new LinkedHashSet<>(configCandidates); // 儲存已解析過的配置類 Set alreadyParsed = new HashSet<>(configCandidates。size()); // 迴圈解析 do { StartupStep processConfig = this。applicationStartup。start(“spring。context。config-classes。parse”); // 解析所有@Configuration標記Bean,並將解析的Bean資訊存入ConfigurationClassParser的configurationClasses集合中 parser。parse(candidates); parser。validate(); Set 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()); } // 初始化所有配置類中的Bean(包含處理ImportBeanDefinitionRegistrars類), // 並將其放入Spring容器中(BeanFactory的beanDefinitionMap) this。reader。loadBeanDefinitions(configClasses); alreadyParsed。addAll(configClasses); processConfig。tag(“classCount”, () -> String。valueOf(configClasses。size()))。end(); candidates。clear(); …… } while (!candidates。isEmpty()); ……}

透過呼叫ConfigurationClassParser#parse對@Configuration類進行解析。

ConfigurationClassParser

public void parse(Set configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder。getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { // Configuration類為AnnotatedBean 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()); } } …… } this。deferredImportSelectorHandler。process();}protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);}protected void processConfigurationClass(ConfigurationClass configClass, Predicate filter) throws IOException { // 判斷是否需要跳過該配置類的解析(例如配置了@Conditional註解) if (this。conditionEvaluator。shouldSkip(configClass。getMetadata(), ConfigurationPhase。PARSE_CONFIGURATION)) { return; } // 標識該配置類是否解析過 ConfigurationClass existingClass = this。configurationClasses。get(configClass); …… // Recursively process the configuration class and its superclass hierarchy。 // 將配置類轉為SourceClass類 SourceClass sourceClass = asSourceClass(configClass, filter); // 從當前配置類configClass開始向上沿著類繼承結構逐層執行doProcessConfigurationClass, // 直到遇到的父類是由Java提供的類結束迴圈 do { sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); } while (sourceClass != null); this。configurationClasses。put(configClass, configClass);}@Nullableprotected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate filter) throws IOException { // Component註解存在繼承關係,遞迴處理巢狀類 if (configClass。getMetadata()。isAnnotated(Component。class。getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } …… // 重點來了,在這裡處理Import註解 processImports(configClass, sourceClass, getImports(sourceClass), filter, true); …… // 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;}/** * 處理配置類上搜集到的@Import註解 * @Param configuClass 配置類 * @Param currentSourceClass 當前原始碼類 * @Param importCandidates 所有的@Import註解的value * @Param exclusionFilter 需要排除的類 * @Param checkForCircularImports 是否檢查迴圈匯入 **/private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection importCandidates, Predicate exclusionFilter, boolean checkForCircularImports) { if (importCandidates。isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this。problemReporter。error(new CircularImportProblem(configClass, this。importStack)); } else { // 開始處理配置類configClass上@Import所有的importCandidates this。importStack。push(configClass); try { // 迴圈處理每一個@Import,每個@Import可能匯入三種類型的類 : // 1。 ImportSelector // 2。 ImportBeanDefinitionRegistrar // 3。 其他型別,都當作配置類處理,也就是相當於使用了註解@Configuration的配置類 // 下面的for迴圈中對這三種情況執行了不同的處理邏輯 for (SourceClass candidate : importCandidates) { // 處理ImportSelector類(Spring Boot的自動裝配採用的是這種方式) if (candidate。isAssignable(ImportSelector。class)) { // 載入對應的ImportSelector實現類 Class<?> candidateClass = candidate。loadClass(); // 例項化對應的實現ImportSelector的類 ImportSelector selector = ParserStrategyUtils。instantiateClass(candidateClass, ImportSelector。class, this。environment, this。resourceLoader, this。registry); // 獲取ImportSelector類中需要排除的例項化的類 Predicate selectorFilter = selector。getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter。or(selectorFilter); } // 後置處理類交由後置處理器進行處理,本類涵蓋程式碼的第18行程式碼處理(this。deferredImportSelectorHandler。process();) if (selector instanceof DeferredImportSelector) { this。deferredImportSelectorHandler。handle(configClass, (DeferredImportSelector) selector); } else { // 呼叫實現ImportSelector的類的selectImports,獲取需要例項化類的className String[] importClassNames = selector。selectImports(currentSourceClass。getMetadata()); // 從當前ImportSelector需要例項化的類開始向上沿著類繼承結構逐層執行將className加入到BeanFactory的beanDefinitionMap中(要排除的類除外), // 直到遇到的父類是由Java提供的類結束迴圈 Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 迴圈處理importClassNames類中再包含的import類 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, 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 類 ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils。instantiateClass(candidateClass, ImportBeanDefinitionRegistrar。class, this。environment, this。resourceLoader, this。registry); // 將ImportBeanDefinitionRegistrar 類加入到importBeanDefinitionRegistrars集合中 // 會在ConfigurationClassPostProcessor第69行程式碼進行處理 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()); // 非ImportSelector or ImportBeanDefinitionRegistrar直接處理,放入BeanFactory中 processConfigurationClass(candidate。asConfigClass(configClass), exclusionFilter); } } } …… }}

透過以上的步驟已將Import中的類注入到BeanFacotry的beanDefinitionMap中等待例項化(ImportBeanDefinitionRegistrar型別的Bean需要透過下面的方式處理才能放入),回到ConfigurationClassPostProcessor的69行程式碼(this。reader。loadBeanDefinitions(configClasses);),呼叫ConfigurationClassBeanDefinitionReader#loadBeanDefinitions進行處理。

ConfigurationClassBeanDefinitionReader

public void loadBeanDefinitions(Set configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); }}private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { …… loadBeanDefinitionsFromImportedResources(configClass。getImportedResources()); // 獲取所有ImportBeanDefinitionRegistrars進行處理 loadBeanDefinitionsFromRegistrars(configClass。getImportBeanDefinitionRegistrars());}private void loadBeanDefinitionsFromRegistrars(Map registrars) { registrars。forEach((registrar, metadata) -> // 呼叫繼承ImportBeanDefinitionRegistrar類中的registerBeanDefinitions將Bean注入到BeanFactory registrar。registerBeanDefinitions(metadata, this。registry, this。importBeanNameGenerator));}

到這一步Import的所有類已註冊到BeanFactory中,那麼什麼時候對這些類進行初始化呢?回到AnnotationConfigApplicationContext(即AbstractApplicationContext)的refresh方法,透過

finishBeanFactoryInitialization(beanFactory)

例項化Bean。