@Condition源码分析及应用

3 篇文章 0 订阅

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);
			}
		}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值