目录
前言
基于springboot2.3.12.RELEASR版本分析
所有的ConditionalOnXXX注解上方都有一个Conditional注解,这个注解的属性是Condition类的实现类。
1、ConfigurationClassParser类解析我们的主启动类的所有注解
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 主启动类的beanDefinition是AnnotatedBeanDefinition的间接子类
// 走这个分支
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 这个就是根据配置类上面的Conditional注解判断是否解析这个配置类
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// Recursively process the configuration class and its superclass hierarchy.
// 如果一个类的父类也是配置类,那么继续解析。
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
// 如果配置类不含有Conditional注解,那么就需要被解析,直接return false
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
// 刚开始传入的phase为PARSE_CONFIGURATION,此if不成立
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<>();
// 遍历Conditional注解的属性(Condition接口的实现类)
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
// 实例化condition接口的实现类
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();
}
// 开始调用前面所有condition实现类的matches方法来决定是否跳过
// Condition接口的一级实现类是SpringBootCondition,所有其他的Conditon实现类
// 都要间接实现SpringBootCondition
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
return false;
}
2、ConditionalOnJava注解属性的Condition接口实现类OnJavaCondition
@Order(Ordered.HIGHEST_PRECEDENCE + 20)
class OnJavaCondition extends SpringBootCondition {
private static final JavaVersion JVM_VERSION = JavaVersion.getJavaVersion();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取ConditionalOnJava注解的属性
Map<String, Object> attributes = metadata
.getAnnotationAttributes(ConditionalOnJava.class.getName());
// range默认为EQUAL_OR_NEWER
Range range = (Range) attributes.get("range");
// value如果我们写的是JavaVersion.NINE,但是我们运行的java版本为1.8
// 那么就不匹配,标注了@ConditionalOnJava的配置类就不会被解析
JavaVersion version = (JavaVersion) attributes.get("value");
return getMatchOutcome(range, JVM_VERSION, version);
}
protected ConditionOutcome getMatchOutcome(Range range, JavaVersion runningVersion,
JavaVersion version) {
boolean match = isWithin(runningVersion, range, version);
String expected = String.format(
(range != Range.EQUAL_OR_NEWER) ? "(older than %s)" : "(%s or newer)",
version);
ConditionMessage message = ConditionMessage
.forCondition(ConditionalOnJava.class, expected)
.foundExactly(runningVersion);
return new ConditionOutcome(match, message);
}
/**
* Determines if the {@code runningVersion} is within the specified range of versions.
* @param runningVersion the current version.
* @param range the range
* @param version the bounds of the range
* @return if this version is within the specified range
*/
private boolean isWithin(JavaVersion runningVersion, Range range,
JavaVersion version) {
// range默认为EQUAL_OR_NEWER
if (range == Range.EQUAL_OR_NEWER) {
return runningVersion.isEqualOrNewerThan(version);
}
if (range == Range.OLDER_THAN) {
return runningVersion.isOlderThan(version);
}
throw new IllegalStateException("Unknown range " + range);
}
}
3、SpringBootCondition类为Condition的直接实现类
public abstract class SpringBootCondition implements Condition {
private final Log logger = LogFactory.getLog(getClass());
@Override
public final boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
String classOrMethodName = getClassOrMethodName(metadata);
try {
//这个方法的返回对象的isMatch布尔属性来解决是否需要解析当前配置类
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
recordEvaluation(context, classOrMethodName, outcome);
return outcome.isMatch();
}
// ...
}
// 模板方法,所有SpringBootCondition继承类需要实现这个方法
public abstract ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata);