我们经常在Spring/SpringBootStarter或者一些框架的源码中看到类似下面的注解,可能是应用于类或者方法:@ConditionalOnProperty(name="spring.cloud.refresh.enabled",matchIfMissing=true)@ConditionalOnProperty(prefix="management.metrics.export.atlas",name="enabled",havingValue="true",matchIfMissing=true)我们一眼就可以看出,这就是“Conditions”。需要满足某个属性存在,或者属性值为xx。对于属性匹配,它会检查当前需要的属性是否包含在环境中。如果没有指定havingValue,则该属性的值不能同时为字符串“false”,其他的都视为true。今天这篇文章,就是一个伏笔。先说一下注解的工作原理。在下一篇文章中,我将写一个与此相关的有趣案例。精简版工作原理会在SpringBoot启动过程中扫描当前依赖中的@Configuration,然后在遍历过程中判断其中哪些是有条件的。对于这些情况,它会判断shouldSkip,这里是否跳过,会根据注解作用于类和方法,转向不同的Metadata,提取对应的实现类,但本质上是去Environment中找这个通过resolver属性是否存在,不存在则跳过,存在则值是否匹配。判断Confirutaion是否生效。对于源码版本,我们知道Spring启动的过程也是创建和初始化Bean的过程。在这个过程中,会先获取到BeanNames,然后逐个创建和初始化。此时,对于Configuration,是通过BeanPostProcessor的方式来处理的.publicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){intregistryId=System.identityHashCode(registry);this.registriesPostProcessed.add(registryId});processConfigBeanDefinitions/里(registry);processConfigBeanDefinitions/registry部分调用栈如下:java.lang.Thread.State:RUNNABLEatorg.springframework.boot.autoconfigure.condition.OnPropertyCondition.getMatchOutcome(OnPropertyCondition.java:65)atorg.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)atorg.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)atorg.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:181)atorg.springframework.context.annotation.ConfigurationClassDefinitionForBeanDefinitionReader(ConfigurationClassBeanDefinitionReader.java:142)atorg.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:118)atorg.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:328)atorg.springframework.context.annotation.ConfigurationClassPostProcessor.postRegiProcessBean(233)这里Class和Method都在这个方法里,处理入口不一样,传入的Meta也不一样configCandidates=newArrayList<>();String[]candidateNames=registry.getBeanDefinitionNames();for(StringbeanName:candidateNames){BeanDefinitionbeanDef=registry.getBeanDefinition(beanName);if(ConfigurationClassUtils.isFullConfigurationClass(beanDef)||ConfigurationClassUtils.isLiteConfiggurationClass(beanDef)){}elseif(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,this.metadataReaderFactory)){configCandidates.add(newBeanDefinitionHolder(beanDef,beanName));}}//Returnimmediatelyifno@Configurationclasseswerefoundif(configCandidates.isEmpty()){return;}//Parseeeach@ConfigurationclassConfigurationClassParserparser=newConfigurationClassParser(this.metadataReaderFactory,this.problemReporter,this.environment,this.resourceLoader,this.componentScanBeanNameGenerator,registry);Set
