在springboot中,有@ConditionalOnClass,@ConditionalOnBean,@ConditionalOnMissingClass,@ConditionalOnMissingBean等注解,这些注解的含义是有某个类或者没有某个bean才会加载,那么源码是在什么地方处理的呢,下面我们一起看下。
我们以类EncryptionBootstrapConfiguration为例,它上面有注解:@ConditionalOnClass({ TextEncryptor.class })。
处理是在ConfigurationClassParser类的processConfigurationClass()方法中:
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
这个方法就是查看是否有满足条件的class或者bean。shoudSkip方法就是判断是否要跳过。这个方法前面都是获取注解的元数据,核心方法是在下面这段:
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;
}
}
这段中首先判断condition是否是ConfigurationCondition类型,这个获取的condition实例的类型是从@ContionalOnClass注解上获取
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
@Conditional(OnBeanCondition.class)
public @interface ConditionalOnBean {
只有OnBeanCondition是ConfigurationCondition类型的,所以只有在@ConditionalOnBean和@ConditionalOnMissingBean的时候requiredPhase才有值,而这个requiredPhase==phase的判断的作用,只是看过滤的时机,是在创建Configuration类的时候过滤还是在创建bean的时候过滤而已。
所以对于所有的注解来说后面的condition.matches(this.context, metadata)方法,都是必走的
@Override
public final boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
String classOrMethodName = getClassOrMethodName(metadata);
try {
ConditionOutcome outcome = getMatchOutcome(context, metadata);
logOutcome(classOrMethodName, outcome);
recordEvaluation(context, classOrMethodName, outcome);
return outcome.isMatch();
}
第一行的getMatchOutcome方法就是通过获取对应的OnBeanCondition或者OnClassCondition获取相应的ConditionOutcome类,然后执行isMathc()方法来判断是否跳过。
有一篇相关博客介绍的不错推荐给大家:https://www.jianshu.com/p/c4df7be75d6e