这些不知道,别说你熟悉 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,二者配合完成配置中心的接入 。

推荐阅读