Spring @Conditional 注解的使用和原理

前言

熟悉 SpringBoot 的小伙伴们肯定不会对 @Conditional 注解感到陌生,它在 SpringBoot 的自动化配置特性中起到了非常重要的作用。许多配置类在加载 Bean 时都使用到了 @ConditionalOnClass、@ConditionalOnBean,@ConditionalOnProperty 等 @Conditional 的衍生注解。
那么,在单纯的 Spring 项目中,我们是否也可以使用 @Conditional 来实现一些自动化配置的特性呢?我们该怎么样去使用@Conditional? 它又是如何生效的?别着急,本篇文章会一一解答。

概述

@Conditional 在 Spring 4.0 中被引入,用于开发 “If-Then-Else” 类型的 bean 注册条件检查。在 @Conditional 之前,也有一个注解 @Porfile 起到类似的作用,它们两个的区别在于:

  • @Profile 仅用于基于环境变量的条件检查,使用范围比较窄。
  • @Conditional 更加通用,开发人员可以自定义条件检查策略。可用于 bean 注册时的条件检查。
  • 4.3.8后,@Profile 也基于 @Conditional 来实现。

用法

首先来看一下源码中 @Conditional 的定义

package org.springframework.context.annotation;

@Target({
   ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
   
	Class<? extends Condition>[] value();
}

根据定义, @Conditional 可以使用在类或方法上,具体的用法有:

  • 作为类注解,标注在直接或间接使用了 @Component 的类上,包括 @Configuration 类
  • 作为元注解,直接标注在其他的注解上面,用于编写自定义注解
  • 作为任何 @Bean 方法的方法级注解

@Conditional 有一个属性 value,其类型是 Condition 数组。组件必须匹配数组中所有的 Condition,才可以被注册。

package org.springframework.context.annotation;

@FunctionalInterface
public interface Condition {
   
    /**
	 * 判断条件是否匹配
	 * @param context 上下文信息,可以从中获取 BeanDefinitionRegistry,BeanFactory,Environment,ResourceLoader,ClassLoader 等一些用于资源加载的信息
	 * @param metadata 注解的元信息,可以从中获取注解的属性
	 * @return {@code true} 条件匹配,组件可以注册
	 * or {@code false} 否决组件的注册
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

Condition 是一个函数式接口,只有一个 matches 方法,返回 true 则表示条件匹配。matches 方法的两个参数分别是上下文信息和注解的元信息,从这两个参数中可以获取到 IOC 容器和当前组件的信息,从而判断条件是否匹配。
由于 ConditionContext 和 AnnotatedTypeMetadata 的方法都比较简单,这里就不贴出源码了,有兴趣的小伙伴可自行翻看源码。
Condition 必须遵循与 BeanFactoryPostProcessor 相同的限制,并注意永远不要与 bean 实例交互。如果要对与 @Configuration bean 交互的条件进行更细粒度的控制,可以考虑 ConfigurationCondition 接口。

public interface ConfigurationCondition extends Condition {
   
    /**
	 * 返回条件生效的阶段
	 */
    ConfigurationPhase getConfigurationPhase();

    enum ConfigurationPhase {
   
        /**
		 * 在 @Configuration 类解析时生效
		 */
        PARSE_CONFIGURATION,
        /**
		 * 在 bean 注册时生效。此时所有的 @Configuration 都解析完成了。
		 */
        REGISTER_BEAN
        }
}

接下来我们在 Spring 下实现一个简单的 ConditionalOnBean 注解,实现一个 bean 只有在另一个 bean 存在时,才进行注册。

@Target({
    ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
&
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值