@Conditional 是 Spring 4 提供的新注解,它的作用是按照一定的条件进行判断,当满足条件时会给容器注册 bean。举个例子,比如说我们有一个接口,这个接口有多个实现类,当我们将这个接口交给 Spring 容器管理时通常只能选择其中一个作为实现类,但是我们又希望能够根据不同的情况注册不同的实现类,此时就可以使用该注解。
/** * All {@link Condition Conditions} that must {@linkplain Condition#matches match} * in order for the component to be registered. */ Class<? extendsCondition>[] value();
}
可以看到,该注解可以在类、接口、注解、枚举以及方法上使用,并且该注解在编译和运行时都有效。该注解在使用时需要传入一个 Class 数组,数组元素的类型要求必须是 Condition 类型或它的子类。接下来我们查看 Condition 接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@FunctionalInterface publicinterfaceCondition {
/** * Determine if the condition matches. * @param context the condition context * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class} * or {@link org.springframework.core.type.MethodMetadata method} being checked * @return {@code true} if the condition matches and the component can be registered, * or {@code false} to veto the annotated component's registration */ booleanmatches(ConditionContext context, AnnotatedTypeMetadata metadata);
在 Spring 的整个体系当中,广泛使用 @Conditional 注解家族成员的就是 Spring Boot,因为 Spring Boot 包含大量的自动配置类,它们需要根据不同的条件选择性地注册到 Spring 容器当中。因此接下来我们就根据 Spring Boot 继续向下分析,先查看实现了 Condition 接口的类 SpringBootCondition。
@Override publicfinalbooleanmatches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 根据元数据获取当前类或者方法的名称 StringclassOrMethodName= getClassOrMethodName(metadata); try { // 获取条件匹配的结果 ConditionOutcomeoutcome= getMatchOutcome(context, metadata); // 打印日志 logOutcome(classOrMethodName, outcome); // 暂存结果数据 recordEvaluation(context, classOrMethodName, outcome); // 返回结果 return outcome.isMatch(); } catch (NoClassDefFoundError ex) { thrownewIllegalStateException("Could not evaluate condition on " + classOrMethodName + " due to " + ex.getMessage() + " not " + "found. Make sure your own configuration does not rely on " + "that class. This can also happen if you are " + "@ComponentScanning a springframework package (e.g. if you " + "put a @ComponentScan in the default package by mistake)", ex); } catch (RuntimeException ex) { thrownewIllegalStateException("Error processing condition on " + getName(metadata), ex); } }