@Conditional注解的详解和应用

一、@Conditional注解的作用

该注解是Spring4.0之后才有的,该注解可以放在任意类型或者方法上。通过@Conditional可以配置一些条件判断,当所有条件都满足时,被该@Conditional注解标注的目标才会被Spring处理。
注解源码:

@Target({
   
   ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Document
public @interface Confitional{
   
   
	Class<? extend Condition> [] value();
}
  • value:Condition类型的数组,Condition是一个接口,表示一个条件判断,内部有个方法返回true或false,当所有Condition都成立的时候,@Conditional的结果才成立

Condition接口:
内部有个match方法,判断条件是否成立的。

@FunctionalInterface
public interface Condition {
   
   
    //判断条件是否匹配 context:条件判断上下文
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

有两个参数:contextmetadata

  • context:ConditionContext 接口类型的,用来获取容器中的bean的信息
  • metadata:用来获取被@Conditional标注的对象上的所有注解信息。

ConditionContext接口

public interface ConditionContext {
   
   
    //返回bean定义注册器,可以通过注册器获取bean定义的各种配置信息
    BeanDefinitionRegistry getRegistry();
    //返回ConfigurableListableBeanFactory类型的bean工厂,相当于一个ioc容器对象
    @Nullable
    ConfigurableListableBeanFactory getBeanFactory();
    //返回当前spring容器的环境配置信息对象
    Environment getEnvironment();
    //返回资源加载器
    ResourceLoader getResourceLoader();
    //返回类加载器
    @Nullable
    ClassLoader getClassLoader();
}

二、条件判断在什么时候执行?

2.1 什么是配置类?

类上面有@Configuration,@Component,@ComponentScan,@Import,@Bean,@ImportResource这些注解时,被标注的类就是配置类.

//判断一个类是不是一个配置类,是否的是下面这个方法,有兴趣的可以看一下:
//org.springframework.context.annotation.ConfigurationClassUtils#isConfigurationCandidate
public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
   
   
	// Do not consider an interface or an annotation...
	if (metadata.isInterface()) {
   
   
		return false;
	}

	// Any of the typical annotations found?
	for (String indicator : candidateIndicators) {
   
   
		if (metadata.isAnnotated(indicator)) {
   
   
			return true;
		}
	}

	// Finally, let's look for @Bean methods...
	return hasBeanMethods(metadata);
}

static boolean hasBeanMethods(AnnotationMetadata metadata) {
   
   
		try {
   
   
			return metadata.hasAnnotatedMethods(Bean.class.getName());
		}
		catch (Throwable ex) {
   
   
			if (logger.isDebugEnabled()) {
   
   
				logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
			}
			return false;
		}
	}

2.2 Spring对配置类的处理阶段

配置类解析阶段:
得到一些配置类信息,和一批需要注册的bean
bean的注册阶段:
将配置类解析阶段得到的配置类作为bean和配置类里需要注册的bean都注册到容器中

2.3 @Conditional使用的步骤

  • 自定义一个类,实现Condition或ConfigurationCondition接口,实现matches方法
  • 在目标对象上使用@Conditional注解,并指定value的指为自定义的Condition类型
  • 启动spring容器加载资源,此时@Conditional就会起作用了

2.4 @Conditional条件判断在什么时候执行

  1. 在配置类上加@Conditional注解,来控制这个配置类是否需要被解析,如果配置类不解析,则配置类上面的上面6个注解的解析都会被跳过。
  2. 在被注册的bean上加@Conditional注解,来控制这个bean是否需要被注册到Spring容器中。
  3. 当配置类不需要被注册到容器时,那这个配置类解析所产生的新的配置类和所产生的新的bean都不会被注册到容器中

总结
(1)@Conditional的参数是实现了Condition接口的类。
(2)当@Conditional放在需要被控制注册的bean上时,则只是被标注的bean不会被注册,配置类和其他bean会被注册。
(3)当@Conditional放在配置类上时,那么实现类里的条件对两个阶段都有效,此时无法精确控制具体某个阶段;如果想要具体控制某个阶段,比如可以解析,但不让注册bean,此时需要用到ConfigurationCondition接口
ConfigurationCondition接口
该接口是Condition接口的子类,getConfigurationPhase方法用来指定条件判断的阶段,
判断是在解析配置类的时候过滤还是在注册bean的时候过滤

public interface ConfigurationCondition extends Condition {
   
   
    /**
     * 条件判断的阶段,是在解析配置类的时候过滤还是在创建bean的时候过滤
     */
    ConfigurationPhase getConfigurationPhase();

    /**
     * 表示阶段的枚举:2个值
     */
    enum ConfigurationPhase {
   
   
        /**
         * 配置类解析阶段,如果条件为false,配置类将不会被解析
         */
        PARSE_CONFIGURATION,
        /**
         * bean注册阶段,如果为false,bean将不会被注册
         */
        REGISTER_BEAN
    }
}

三、案例

3.1 阻止配置类的解析

1、自定义Condition接口的实现类:
Condition实现类中当有一个条件为false的时候,spring就会跳过处理这个配置类

public class ConditionImpl implements Condition {
   
   
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
   
   
        return false;
    }
}

2、配置类

@Configuration
@Conditional(ConditionImpl.class)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一位不知名民工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值