@Conditional介绍
@Conditional注解用于按照设定的条件进行判断,从而决定是否将某个bean注册到Spring容器中。
@Conditional注解是在Spring 4.0版本中引入的,它提供了一种更加灵活的方式来控制bean的创建和注册。在此之前,开发者通常使用@Profile注解来根据不同的环境配置来加载不同的bean,但@Profile的使用范围相对有限,仅适用于基于环境变量的条件检查。而@Conditional注解则更加通用,允许开发者自定义条件检查策略,从而实现更复杂的条件逻辑。
这个注解可以用于类级别,也可以用于方法级别。
要使用@Conditional注解,你需要创建一个实现了Condition接口的类,并重写matches方法来定义你的条件判断逻辑。当matches方法返回true时,对应的bean将会被注册到Spring容器中;如果返回false,则不会注册。这种机制使得你可以根据应用的配置、环境变量或其他任何条件来决定是否创建某个bean实例。
@Conditional
注解可以与以下条件类一起使用
-
OnClassCondition
:检查类路径中是否存在指定的类。 -
OnMissingClassCondition
:检查类路径中是否不存在指定的类。 -
OnBeanCondition
:检查Spring容器中是否存在指定的Bean。 -
OnMissingBeanCondition
:检查Spring容器中是否不存在指定的Bean。 -
OnPropertyCondition
:检查系统属性或环境变量是否满足指定的条件。 -
OnResourceCondition
:检查类路径中是否存在指定的资源。 -
OnWebApplicationCondition
:检查是否是Web应用程序环境。
@Conditional
源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
源代码截图
@Conditional
属性介绍
- value:指定Condition接口的实现类,Condition接口的实现类中需要编写具体代码实现向Spring中注入Bean的条件
@Conditional
注解使用场景
@Conditional
注解的使用场景主要体现在以下几个方面:
- 基于属性配置的条件注入:使用
@ConditionalOnProperty
可以根据指定的属性是否存在或是否具有特定的值来决定是否创建和注册Bean。这在需要根据配置文件动态决定是否启用某个功能时非常有用。 - 基于Bean存在的条件注入:
@ConditionalOnBean
注解可以用来检查Spring上下文中是否已经存在某个Bean,如果存在,则创建和注册新的Bean。这在需要某个Bean作为依赖时尤其有用。 - 基于类存在的条件注入:
@ConditionalOnClass
注解用于检查某个类是否在类路径中可用,如果可用,则进行Bean的创建和注册。这在自动配置和模块加载时非常有用。 - 基于资源存在的条件注入:
@ConditionalOnResource
注解允许你根据特定资源的存在与否来决定是否创建和注册Bean。这在需要外部资源(如文件、URL等)时很有帮助。 - 基于Web环境的条件注入:
@ConditionalOnWebApplication
注解用于确保只有在Web环境中才会创建和注册Bean,这对于Web特定功能的自动配置非常有用。 - 基于SpEL表达式的条件注入:
@ConditionalOnExpression
注解允许你使用Spring Expression Language (SpEL) 来定义复杂的条件表达式,从而控制Bean的创建和注册。 - 自定义条件实现:你可以自定义实现
Condition
接口的类,通过实现matches
方法来定义自己的条件逻辑。这种方式提供了最大的灵活性,允许你根据任何复杂的条件来决定Bean的创建
@Conditional
测试示例代码
示例代码 一
ConditionalDemo类
package com.yang.SpringTest.annotation.conditionalLearn;
import lombok.Data;
/**
* <p>description</p>
*
* @author By: chengxuyuanshitang
* Package com.yang.SpringTest.annotation.conditionalLearn
* Ceate Time 2024-03-20 14:55
*/
@Data
public class ConditionalDemo {
}
ConditionalDemoCondition类
package com.yang.SpringTest.annotation.conditionalLearn;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* <p>description</p>
*
* @author By: chengxuyuanshitang
* Package com.yang.SpringTest.annotation.conditionalLearn
* Ceate Time 2024-03-20 14:52
*/
public class ConditionalDemoCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String osName = context.getEnvironment().getProperty("sun.desktop");
return osName.contains("windows") ? true : false;
}
}
ConditionalDemoConfig配置类
package com.yang.SpringTest.annotation.conditionalLearn;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
/**
* <p>配置类</p>
*
* @author By: chengxuyuanshitang
* Package com.yang.SpringTest.annotation.conditionalLearn
* Ceate Time 2024-03-20 14:54
*/
@Slf4j
@Configuration
@Conditional(ConditionalDemoCondition.class)
public class ConditionalDemoConfig {
@Bean
public ConditionalDemo demo() {
log.info("------------- ConditionalDemo init -------------");
return new ConditionalDemo();
}
}
ConditionalTest测试类
package com.yang.SpringTest.annotation.conditionalLearn;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.Arrays;
/**
* <p>测试类</p>
*
* @author By: chengxuyuanshitang
* Package com.yang.SpringTest.annotation.conditionalLearn
* Ceate Time 2024-03-20 14:58
*/
public class ConditionalTest{
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionalDemoConfig.class);
String[] definitionNames = context.getBeanDefinitionNames();
Arrays.stream(definitionNames).forEach((definitionName) -> System.out.println(definitionName));
}
}