Spring-@Conditional

SpringBoot的AutoConfig内部大量使用了@Conditional,会根据运行环境来动态注入Bean。

@Conditional是SpringFramework的功能,SpringBoot在它的基础上定义了@ConditionalOnClass, @ConditionalOnProperty的一系列注解来实现丰富的内容。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {

	/**
	 * The classes that must be present. Since this annotation is parsed by loading class
	 * bytecode, it is safe to specify classes here that may ultimately not be on the
	 * classpath, only if this annotation is directly on the affected component and
	 * <b>not</b> if this annotation is used as a composed, meta-annotation. In order to
	 * use this annotation as a meta-annotation, only use the {@link #name} attribute.
	 * @return the classes that must be present
	 */
	Class<?>[] value() default {};

	/**
	 * The classes names that must be present.
	 * @return the class names that must be present.
	 */
	String[] name() default {};

}

OnClassCondition则继承了SpringBootCondition,而SpringBootCondition实现了Condition接口。查看SpringFramework的源码会发现加载使用这些注解的入口在ConfigurationClassPostProcessor中,这个实现了BeanFactoryPostProcessor接口,它会嵌入到Spring的加载过程。这个类主要是从ApplicationContext中取出Configuration注解的类并解析其中的注解,包括@Conditional, @Import, @Bean等。

解析@Conditional逻辑在ConfigurationClassParser类中,这里面用到了ConditionEvaluator这个类。

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            return;
        }
        ......
    }

ConditionEvaluator中的shouldSkip方法则使用了@Conditional中设置的Condition类。

public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
        if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
            return false;
        }
        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<Condition>();
        for (String[] conditionClasses : getConditionClasses(metadata)) {
            for (String conditionClass : conditionClasses) {
                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();
            }
            if (requiredPhase == null || requiredPhase == phase) {
                if (!condition.matches(this.context, metadata)) {
                    return true;
                }
            }
        }
        return false;
    }
    private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
            MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(Conditional.class.getName(), true);
            Object values = (attributes != null ? attributes.get("value") : null);
            return (List<String[]>) (values != null ? values : Collections.emptyList());
    }

猜你喜欢

转载自blog.csdn.net/chs007chs/article/details/80254838
今日推荐