@Contition注解的使用


title: spring Condition 注解
date: 2020-10-23 15:34:11
tags: ["Spring,注解,Condition"]


@Condition 作用

@Condition 可作用于方法或者类上,用于是否注册组件对象。
理解: 就是添加了这个注解,spring 会解析这个注解,然后判断当前注册的bean是否应该注册。
或者当前类是否应该注册!

@Condition 分析

/**
 * Indicates that a component is only eligible for registration when all
 * {@linkplain #value specified conditions} match.
 *
 * <p>A <em>condition</em> is any state that can be determined programmatically
 * before the bean definition is due to be registered (see {@link Condition} for details).
 *
 * <p>The {@code @Conditional} annotation may be used in any of the following ways:
 * <ul>
 * <li>as a type-level annotation on any class directly or indirectly annotated with
 * {@code @Component}, including {@link Configuration @Configuration} classes</li>
 * <li>as a meta-annotation, for the purpose of composing custom stereotype
 * annotations</li>
 * <li>as a method-level annotation on any {@link Bean @Bean} method</li>
 * </ul>
 *
 * <p>If a {@code @Configuration} class is marked with {@code @Conditional},
 * all of the {@code @Bean} methods, {@link Import @Import} annotations, and
 * {@link ComponentScan @ComponentScan} annotations associated with that
 * class will be subject to the conditions.
 *
 * <p><strong>NOTE</strong>: Inheritance of {@code @Conditional} annotations
 * is not supported; any conditions from superclasses or from overridden
 * methods will not be considered. In order to enforce these semantics,
 * {@code @Conditional} itself is not declared as
 * {@link java.lang.annotation.Inherited @Inherited}; furthermore, any
 * custom <em>composed annotation</em> that is meta-annotated with
 * {@code @Conditional} must not be declared as {@code @Inherited}.
 *
 * @author Phillip Webb
 * @author Sam Brannen
 * @since 4.0
 * @see Condition
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {

    /**
     * All {@link Condition}s that must {@linkplain Condition#matches match}
     * in order for the component to be registered.
     */
    Class<? extends Condition>[] value();

}

这里可能要涉及到一些注解相关的知识:
ElementType.TYPE 这里可以点进去看一下,官方的解释很好理解,:
可作用于 类,接口,包括注解(可用作混合注解),或者 枚举声明
/** Class, interface (including annotation type), or enum declaration */
ElementType.METHOD : 作用于方法声明
按照 @Condition 来分析参数默认只能填入一个 Condition 数组,尝试去看一下 Condition,发现是一个接口,如下:

/**
     * 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
     */
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

如何使用 @Condition ?

如下代码:

/**
 * @author cayden
 * @version V1.0
 * @date 2020/10/22 14:10
 */
public class ConditionOwn implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 上下文需要的 context
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        // 运行环境
        Environment environment = context.getEnvironment();
        if (environment.getProperty("os.name").contains("Windows")){
            return true;
        }

        return false;
    }
}

核心其实就是我们要重写 Condition的 matches方法,然后返回是否需要加载就行了,这里所拿道德参数很关键,
metadata是源注解,是当前类的注解,你可以解析匹配某个注解返回
environment: environment 是运行环境,具体可研究代码

注解到类上面

/**
 * @author cayden
 * @date 2020/3/16 15:09
 * 注意,如果实现了BeanFactoryPostProcessor 或者他的子类接口 BeanDefinitionRegistryPostProcessor
 * 在实现 BeanPostProcessor 的时候,是不能取到当前类的
 */
@Component
@Conditional(value = ConditionOwn.class)
@Order(value = 1)
public class Dao implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 实现 beanFactoryPostProcessor 可以拿到bean的定义然后干预 spring bean 的生命周期
        BeanDefinition dao = beanFactory.getBeanDefinition("nothing");
        System.out.println(dao.isSingleton());
    }

    public void print(){
        System.out.println("i'm dao !");
    }
}

注解在方法上

@Bean
    @Conditional(ConditionOwn.class)
    public TestBean createTestBean(){
        return new TestBean();
    }

spring 是如何解析 @Condition 注解的,在什么时候解析的?

/**
     * Determine if an item should be skipped based on {@code @Conditional} annotations.
     * @param metadata the meta data
     * @param phase the phase of the call
     * @return if the item should be skipped
     */
    public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable 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<>();
        for (String[] conditionClasses : getConditionClasses(metadata)) {
            for (String conditionClass : conditionClasses) {
                Condition condition = getCondition(conditionClass, this.context.getClassLoader());
                conditions.add(condition);
            }
        }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容