1 查找配置是否生效处理代码
上一编可以看到EnableAutoConfiguration 加载的配置类就有92个,但是这个配置类都有效吗,显然是不一定的,因为很多相关的依懒都没有加引进来,又怎么生效呢?哪问题来了,spring-boot 是如何去处理的呢,带着这些疑问又该怎么入手分析?
a、首先确定处理的代码范围,逐渐缩小范围,b或先观察配置类身上的信息
在前面分析ConfigurationClassPostProcessor.processConfigBeanDefinitions()方法内可以看到这么一下段代码
//parser.getConfigurationClasses() 从spring-factories获取获取到的配置类信息
Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//ConfigurationClassBeanDefinitionReader 这里疑似是把配置类转换成beandefinition再注册到beanfactory里
this.reader.loadBeanDefinitions(configClasses);
继续跟下去查看一下ConfigurationClassBeanDefinitionReader这个里面有什么
/**
* Reads a given fully-populated set of ConfigurationClass instances, registering bean
* definitions with the given {@link BeanDefinitionRegistry} based on its contents.
上面的意思读取所有配置类实例,并根据其内容器注册beandefinitions
2 处理是否有效配置
/**
* Read a particular {@link ConfigurationClass}, registering bean definitions
* for the class itself and all of its {@link Bean} methods.
*/
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
TrackedConditionEvaluator trackedConditionEvaluator) {
//1.根据配置类身上的Conditional是否满足(依懒是否有引入)注册到beanfactory里,这是重点
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName());
return;
}
//2.如果是导入类,直接注册其自身
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
//3.遍历配置类上所有的@Bean方法返回的bean并注册
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//4.导入资源配置如:@ImportResource(locations={"classpath:spring-beans.xml"})
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
3 @conditional 处理
回头到1.1去观一下配置类的都一些特点,配置类身上都有@Conditional注解或其子类,好像上面那段代码第1点注释就是处理@Conditional注解的
private class TrackedConditionEvaluator {
private final Map<ConfigurationClass, Boolean> skipped = new HashMap<ConfigurationClass, Boolean>();
public boolean shouldSkip(ConfigurationClass configClass) {
Boolean skip = this.skipped.get(configClass);
if (skip == null) {
if (configClass.isImported()) {
boolean allSkipped = true;
for (ConfigurationClass importedBy : configClass.getImportedBy()) {
if (!shouldSkip(importedBy)) {
allSkipped = false;
break;
}
}
if (allSkipped) {
// The config classes that imported this one were all skipped, therefore we are skipped...
skip = true;
}
}
if (skip == null) {
skip = conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN);
}
this.skipped.put(configClass, skip);
}
return skip;
}
}
ConditionEvaluator 很明显该类是用处理配置类是否满自动配置(jar依懒条件是否被引用等),继续贴代码
/**
* Determine if an item should be skipped based on {@code @Conditional} annotations.
* @param metadata the meta data
* @param phase the phase of the call
* @return if the item should be skipped
*/
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationCondition.ConfigurationPhase phase) {
//不存注解或没存在Conditional注解返回(不跳过)
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
if (phase == null) {
//因为这里是递归处理,传入的不身上有@Configuration注解,不一定为配置类,所以为判断一下
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
//@Configuration 配置类的处理
return shouldSkip(metadata, ConfigurationCondition.ConfigurationPhase.PARSE_CONFIGURATION);
}
//只有@condition注解的处理
return shouldSkip(metadata, ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN);
}
//遍历身上所有@Conditional 注解
List<Condition> conditions = new ArrayList<Condition>();
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition);
}
}
AnnotationAwareOrderComparator.sort(conditions);
//匹配所有condition,只有一个条件不满足,该类及就不会被注册到beanfactory里
for (Condition condition : conditions) {
ConfigurationCondition.ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
if (requiredPhase == null || requiredPhase == phase) {
if (!condition.matches(this.context, metadata)) {
return true;
}
}
}
return false;
}
到此spring-boot 自动配置疑云应该都解开了