Spring原始碼閱讀 - @Import一個繼承 ImportBeanDefinitionRegistrar 的類
阿新 • • 發佈:2022-04-10
1. ImportBeanDefinitionRegistrar
// 和 DeferredImportSelectors 類似, 也可以自己註冊 BeanDefinition // 不過這個介面可以繼承 EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware, 或者提供引數為 Environment、... 的建構函式\ // 不過也只是經過了特殊的的初始化, 和普通 Bean 通過 getBean 經過完整生命週期還是不一樣的 public interface ImportBeanDefinitionRegistrar { // 註冊BD, 預設行為啥也不做 // 不建議在這裡注入 BeanDefinitionRegistryPostProcessor, 因為處理到他的時候, 配置類的處理流程已經完畢【??待續後續程式碼】 default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { registerBeanDefinitions(importingClassMetadata, registry); } default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
2. 處理流程
org.springframework.context.annotation.ConfigurationClassParser#processImports
// Import 的類繼承了 ImportSelector 介面 if (candidate.isAssignable(ImportSelector.class)) { // ... ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); // ... } // 繼承了 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(); // 例項化, 這個呼叫和上面的呼叫是一致的, 也就是說 ImportSelector 也可以繼承一些 Aware 介面, 或提供建構函式 ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 也沒有立即處理, 注意這裡是放到 configClass 中的 // 而 DeferredImportSelector 是放到了一個集合中 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); }
3. 處理時機
注意上面是將這個 ImportBeanDefinitionRegistrar 繫結在了 configClass 中,從這就可看出它的執行應該是較晚的,實際比 DeferredImportSelector 還晚。
回到 ConfigurationClassPostProcessor#processConfigBeanDefinitions
do { // 這裡是解析配置類, DeferredImportSelector 就是在裡面就被呼叫了 parser.parse(candidates); parser.validate(); // 這裡面應該是 Parser 記錄的解析過的配置類 Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); // 去除已經解析過的,這個實際主要是用在後面 loadBeanDefinitions 去除不必要的 BD, removeAll 是為了減少判斷 // alreadyParsed 是上一次迴圈已經解析過的,去除上一次解析過的就是這一次解析過的,主要是 Parser 是複用的,所以需要 removeAll 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()); } // 這裡就處理了 ImportBeanDefinitionRegistrar, 遲於 DeferredImportSelector this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); // ... } while (!candidates.isEmpty());