Spring原始碼閱讀 - @Import 一個繼承 ImportSelector 介面的類
阿新 • • 發佈:2022-04-09
處理邏輯在 org.springframework.context.annotation.ConfigurationClassParser#processImports
。
暫時略其子介面 DeferredImportSelector
1. ImportSelector 介面
selectImports 方法返回的字串陣列,每個字串被視為一個要被注入容器的類的全限定名。
public interface ImportSelector { /** * Select and return the names of which class(es) should be imported based on * the {@link AnnotationMetadata} of the importing @{@link Configuration} class. * @return the class names, or an empty array if none */ String[] selectImports(AnnotationMetadata importingClassMetadata); /** * Return a predicate for excluding classes from the import candidates, to be * transitively applied to all classes found through this selector's imports. * <p>If this predicate returns {@code true} for a given fully-qualified * class name, said class will not be considered as an imported configuration * class, bypassing class file loading as well as metadata introspection. * @return the filter predicate for fully-qualified candidate class names * of transitively imported configuration classes, or {@code null} if none * @since 5.2.4 */ @Nullable default Predicate<String> getExclusionFilter() { return null; } }
2. 處理邏輯
先例項化這個被匯入的類,然後執行 selectImports,根據全限定名陣列載入 class 陣列,並將這些 class 當做配置類解析一遍。
注意到這個被匯入的類直接被例項化了,BD 沒有注入容器,例項也沒有注入容器。
問題: 匯入的 class 陣列被當做配置類解析,但是沒有被注入容器啊,注入容器的時機在哪?
// 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) { // ... } else { // 否則立即處理,將返回的字串陣列當做類全限定名陣列,載入對應的 class 入記憶體 // 傳入的資訊是使用了 @Import 註解的類的資訊 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 把這些載入的類當做直接 @Import 的類進行處理,注意到原 @Import 的類並未被注入容器 processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } }