這些不知道,別說你熟悉 Spring( 三 )


protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)throws IOException {// Process any @PropertySource annotations// Process any @ComponentScan annotations// Process any @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), filter, true);// Process any @ImportResource annotations// Process individual @Bean methodsSet<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// Process default methods on interfacesprocessInterfaces(configClass, sourceClass);// Process superclass, if anyif (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 recursereturn sourceClass.getSuperClass();}}// No superclass -> processing is completereturn null; }1)parser.parse(candidates) 解析得到完整的 ConfigurationClass 對象 , 主要填充下圖框中的四部分 。

這些不知道,別說你熟悉 Spring

文章插圖

這些不知道,別說你熟悉 Spring

文章插圖
2)this.reader.loadBeanDefinitions(configClasses) 根據框中的四部分進行 BeanDefination 的注冊 。
這些不知道,別說你熟悉 Spring

文章插圖
在上述 processImports() 過程中會將 DeferredImportSelector 的實現類放在 deferredImportSelectorHandler 中以便延遲到所有的解析工作完成后進行處理 。deferredImportSelectorHandler 中就存放了 AutoConfigurationImportSelector 類的實例 。process() 方法里經過幾步走會調用到 AutoConfigurationImportSelector#getAutoConfigurationEntry() 方法上獲取到自動裝配需要的類,然后進行與上述同樣的 ConfigurationClass 解析封裝工作 。
這些不知道,別說你熟悉 Spring

文章插圖

這些不知道,別說你熟悉 Spring

文章插圖
代碼層次太深,調用太復雜,建議自己斷點調試源碼跟一遍印象會更深刻 。
ApplicationContextInitializer 調用時機我們就以 SpringBoot 項目為例來看,在 SpringApplication 的構造函數中會進行 ApplicationContextInitializer 的初始化 。
這些不知道,別說你熟悉 Spring

文章插圖
上圖中的 getSpringFactoriesInstances 方法內部其實就是調用 SpringFactoriesLoader.loadFactoryNames 獲取所有 ApplicationContextInitializer 接口的實現類 , 然后反射創建對象,并對這些對象進行排序(實現了 Ordered 接口或者加了 @Order 注解) 。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances; }至此 , 項目中所有 ApplicationContextInitializer 的實現已經加載并且創建好了 。在 prepareContext 階段會進行所有已注冊的 ApplicationContextInitializer#initialize() 方法的調用 。在此之前prepareEnvironment 階段已經準備好了環境信息,此處接入配置中心就可以拉到遠程配置信息然后填充到 Spring 環境中供應用使用 。
這些不知道,別說你熟悉 Spring

文章插圖
SpringBoot 集成 ApolloApolloApplicationContextInitializer 實現 ApplicationContextInitializer 接口,并且在 spring.factories 文件中配置如下
這些不知道,別說你熟悉 Spring

文章插圖
org.springframework.context.ApplicationContextInitializer=\com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializerinitialize() 方法中會根據 apollo.bootstrap.namespaces 配置的 namespaces 進行配置的拉去,拉去到的配置會封裝成 ConfigPropertySource 添加到 Spring 環境 ConfigurableEnvironment 中 。具體的拉去流程就不展開講了,感興趣的可以自己去閱讀源碼了解 。
SpringCloud 集成 Nacos、Zk、Consul在 SpringCloud 場景下 , SpringCloud 規范中提供了 PropertySourceBootstrapConfiguration 繼承 ApplicationContextInitializer , 另外還提供了個 PropertySourceLocator,二者配合完成配置中心的接入 。

推薦閱讀