概要

SpringBoot通过在注册BeanFactoryProcessor,让IOC容器在refresh阶段执行:
invokeBeanFactoryPostProcessors方法,用以继续注册Bean,然后交给:ConfigurationClassPostProcessor
处理所有配置类. 处理核心步骤如下:
1)处理入口:public void processConfigBeanDefinitions(BeanDefinitionRegistry registry)
2)实际处理类:ConfigurationClassParser
3)自动配置类交给DeferredImportSelectorHandler处理

  1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
  2. ...
  3. this.deferredImportSelectorHandler.process();
  4. }

4) 然后获取@EnableAutoConfiguration的Import类, 委托给:AutoConfigurationImportSelector完成自动导入

  1. @Import(AutoConfigurationImportSelector.class)
  2. public @interface EnableAutoConfiguration {}

5)AutoConfigurationImportSelector#getAutoConfigurationEntry 查找spring.factories配置的
org.springframework.boot.autoconfigure.EnableAutoConfiguration属性列表,然后逐个filter,然后返回最终识别的配置类,此阶段只会按一下三种Filer来过滤:

  1. org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
  2. org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
  3. org.springframework.boot.autoconfigure.condition.OnClassCondition,\
  4. org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

也就是说:如果自动配置类的条件是:@ConditionalOnProperty 此次默认认为也是有效的,不会被过滤。
例如:OnClassCondition表示:当前自动配置类要存在才会被导入。

6)如果每个自动配置类有嵌套的配置类,递归的使用:ConfigurationClassParser#processConfigurationClass与
ConditionEvaluator#shouldSkip查找@Conditional注解,依次检查当前配置类是否可被注册为Bean.
org.springframework.context.annotation.ConditionEvaluator#shouldSkip示例:

查找所有带@Conditional的注解:@ConditionalOnBean, @ConditionalOnClass, @ConditionalOnProperty等,然后依次执行注解的Condition类#matches方法,如果返回false, 则不注册为Bean.

  1. public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
  2. if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
  3. return false;
  4. }
  5. if (phase == null) {
  6. if (metadata instanceof AnnotationMetadata &&
  7. ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
  8. return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
  9. }
  10. return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
  11. }
  12. List<Condition> conditions = new ArrayList<>();
  13. for (String[] conditionClasses : getConditionClasses(metadata)) {
  14. for (String conditionClass : conditionClasses) {
  15. Condition condition = getCondition(conditionClass, this.context.getClassLoader());
  16. conditions.add(condition);
  17. }
  18. }
  19. AnnotationAwareOrderComparator.sort(conditions);
  20. for (Condition condition : conditions) {
  21. ConfigurationPhase requiredPhase = null;
  22. if (condition instanceof ConfigurationCondition) {
  23. requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
  24. }
  25. if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
  26. return true;
  27. }
  28. }
  29. return false;
  30. }

SpringBoot规约

1)【推荐】通过starter开放出去的自动配置类不要被自动扫描,不要配置@ComponentScan注解。
原因是:不是走的自动导入机制,而是走的ClassPathBeanScanner扫描。代码如下:

  1. @SpringBootConfiguration
  2. @EnableAutoConfiguration
  3. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  4. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  5. public @interface SpringBootApplication {
  6. }

SpringBootApplication注解注册的ClassPathBeanDefinitionScanner增加了AutoConfigurationExcludeFilter。用来过滤Bean. 因此扫描到的Bean 也能被被条件机制识别到,从而不会被注册。

  1. protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
  2. for (TypeFilter tf : this.excludeFilters) {
  3. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  4. return false;
  5. }
  6. }
  7. for (TypeFilter tf : this.includeFilters) {
  8. if (tf.match(metadataReader, getMetadataReaderFactory())) {
  9. return isConditionMatch(metadataReader);
  10. }
  11. }
  12. return false;
  13. }

2)【强制】配置类内部的嵌套配置类需要为static class