Spring原始碼閱讀 - @Import 處理
阿新 • • 發佈:2022-04-09
1. 概述
同樣是 org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass 開始
org.springframework.context.annotation.ConfigurationClassParser#processImports 就是處理 @Import 的,並沒有將這個邏輯單獨抽出來,原因應該是內部處理還依賴這個類的東西。
2. @Import
注意到這個註解不是可重複註解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Import { /** * {@link Configuration @Configuration}, {@link ImportSelector}, * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import. */ Class<?>[] value(); }
3. 解析
org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
獲取 @Import 的類
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); // 這裡的這個 visited 後面好像是沒有實際使用到的 Set<SourceClass> visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; } private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { // 這裡不太能理解,為什麼會有多個 @Import 註解 ? for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); // if (!annName.equals(Import.class.getName())) { // 這裡是遞迴呼叫 collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }
處理 @Import
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 { // push 了配置類 this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { // Import 的類繼承了 ImportSelector 介面 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports 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 介面(ImportSelector 的子介面) if (selector instanceof DeferredImportSelector) { // 稍後再處理 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 否則立即處理,將返回的字串陣列當做類全限定名陣列,載入對應的 class 入記憶體 // 傳入的資訊是使用了 @Import 註解的類的資訊 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 把這些載入的類當做直接 @Import 的類進行處理,注意到原 @Import 的類並未被注入容器 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } // 繼承了 ImportBeanDefinitionRegistrar 介面,說明這個類有想自己向容器注入 BD 的想法,比如說 MyBatis 自己收集介面, 自己注入這些介面代理類的 BD 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 中的 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 普通類,這裡的普通類包括 @Import 直接匯入的沒有繼承上面三個介面的類,還有就是 @Import 匯入了繼承 ImportSelector 介面的類要注入的普通類 // 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), 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(); } } }
這裡實際只有 @Import 一個"普通"類和 @Import 一個繼承了 ImportSelector 介面的類的處理邏輯較為明顯,其他的實際都不是很明顯。