概要
SpringBoot通过在注册BeanFactoryProcessor,让IOC容器在refresh阶段执行:
invokeBeanFactoryPostProcessors方法,用以继续注册Bean,然后交给:ConfigurationClassPostProcessor
处理所有配置类. 处理核心步骤如下:
1)处理入口:public void processConfigBeanDefinitions(BeanDefinitionRegistry registry)
2)实际处理类:ConfigurationClassParser
3)自动配置类交给DeferredImportSelectorHandler处理
public void parse(Set<BeanDefinitionHolder> configCandidates) {
...
this.deferredImportSelectorHandler.process();
}
4) 然后获取@EnableAutoConfiguration的Import类, 委托给:AutoConfigurationImportSelector完成自动导入
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
5)AutoConfigurationImportSelector#getAutoConfigurationEntry 查找spring.factories配置的
org.springframework.boot.autoconfigure.EnableAutoConfiguration属性列表,然后逐个filter,然后返回最终识别的配置类,此阶段只会按一下三种Filer来过滤:
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
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.
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
SpringBoot规约
1)【推荐】通过starter开放出去的自动配置类不要被自动扫描,不要配置@ComponentScan注解。
原因是:不是走的自动导入机制,而是走的ClassPathBeanScanner扫描。代码如下:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
SpringBootApplication注解注册的ClassPathBeanDefinitionScanner增加了AutoConfigurationExcludeFilter。用来过滤Bean. 因此扫描到的Bean 也能被被条件机制识别到,从而不会被注册。
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
2)【强制】配置类内部的嵌套配置类需要为static class