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 对象 , 主要填充下图框中的四部分 。

文章插图

文章插图
2)this.reader.loadBeanDefinitions(configClasses) 根据框中的四部分进行 BeanDefination 的注册 。

文章插图
在上述 processImports() 过程中会将 DeferredImportSelector 的实现类放在 deferredImportSelectorHandler 中以便延迟到所有的解析工作完成后进行处理 。deferredImportSelectorHandler 中就存放了 AutoConfigurationImportSelector 类的实例 。process() 方法里经过几步走会调用到 AutoConfigurationImportSelector#getAutoConfigurationEntry() 方法上获取到自动装配需要的类,然后进行与上述同样的 ConfigurationClass 解析封装工作 。

文章插图

文章插图
代码层次太深,调用太复杂,建议自己断点调试源码跟一遍印象会更深刻 。
ApplicationContextInitializer 调用时机我们就以 SpringBoot 项目为例来看,在 SpringApplication 的构造函数中会进行 ApplicationContextInitializer 的初始化 。

文章插图
上图中的 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 环境中供应用使用 。
文章插图
SpringBoot 集成 ApolloApolloApplicationContextInitializer 实现 ApplicationContextInitializer 接口,并且在 spring.factories 文件中配置如下

文章插图
org.springframework.context.ApplicationContextInitializer=\com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer
initialize() 方法中会根据 apollo.bootstrap.namespaces 配置的 namespaces 进行配置的拉去,拉去到的配置会封装成 ConfigPropertySource 添加到 Spring 环境 ConfigurableEnvironment 中 。具体的拉去流程就不展开讲了,感兴趣的可以自己去阅读源码了解 。SpringCloud 集成 Nacos、Zk、Consul在 SpringCloud 场景下 , SpringCloud 规范中提供了 PropertySourceBootstrapConfiguration 继承 ApplicationContextInitializer , 另外还提供了个 PropertySourceLocator,二者配合完成配置中心的接入 。
推荐阅读
- 工厂想采购一套信息化生产执行系统mes,不知道用哪家比较好?
- 【前端必会】不知道webpack插件? webpack插件源码分析BannerPlugin
- 贵人相助面相特征,这些特征你有吗
- 耳朵红代表什么预兆,耳朵红其实可能是这些原因引起的而已
- 孕妇牙痛厉害,晚上都几乎不能入睡的,不知道可以吃阿莫西林吗
- 花呗如何增加额度?这些方法要掌握
- 冬虫夏草颜色有一点变黑了,不知道还可不可以吃
- 怎么开微店 这些小攻略建议看下
- 现在承包土地建大棚种蔬菜听说很赚钱,不知道是否可行?
- 氧化铝厂有些什么岗位?这些岗位有什么特点?待遇如何?