@Conditional注解使用及@ConditionalOnXXX各注解的作用
本文为博主原创,转载请注明 出处:
一。@Conditional注解作用:
必须是 @Conditional 注解指定的条件成立,才会在容器中添加组件,配置类里面的所有配置才会生效
二。@Conditional 衍生注解
@Conditional扩展注解作用 | 判断是否满足指定条件 |
@ConditionalOnBean | 容器中存在指定Bean |
@ConditionalOnMissingBean | 容器中不存在指定Bean; |
@ConditionalOnClass | 系统中有指定的类 |
@ConditionalOnMissingClass | 系统中没有指定的类 |
@ConditionalOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionalOnResource | 类路径下是否存在指定资源文件 |
@ConditionalOnWebApplication | 当前是web环境 |
三。@Conditional注解 的使用
3.1 @Conditional 注解源码解析
@Conditional 注解源码:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? extends Condition>[] value(); }
通过源码可以发现看到该注解的传参值 为一个数组,并且需要继承 Condition 类。
查看 Condition 类的源码:
@FunctionalInterface public interface Condition { boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2); }
Condition 为一个函数式接口,其中只有一个matches 方法,接口的返回类型为boolean 值,通过该boolean 值控制是否加载配置。
3.2 @Conditional 实现控制bean 加载
1. 创建一个bean的实体类:
@Data @AllArgsConstructor public class Person { private String name; private int age; }
2. 通过 @Configuration 注解定义两个person 的bean
@Configuration public class BeanConfiguration { @Bean(name= "java") public Person person1(){ return new Person("java",12); } @Bean(name= "linux") public Person person2(){ return new Person("linux",22); } }
3. 通过单元测试查看两个bean
@SpringBootTest class TestApplicationTests { @Autowired private ApplicationContext applicationContext; @Test void contextLoads() { Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class); personBeanMap.forEach((beanName, beanValue) -> { System.out.println(beanName + "--" + beanValue); }); } }
通过这个单元测试会打印出两行Person bean 的信息
4. 定义 实现 Condition 接口的类,并控制是否加载。
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotatedTypeMetadata; public class WindowsCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Environment environment = conditionContext.getEnvironment(); String property = environment.getProperty("os.name"); if (property.contains("linux")){ return true; } return false; } }
并在定义Bean 的BeanConfiguration 类中使用 @Condition 注解实现bean 是否加载
import com.example.test.entity.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class BeanConfiguration { @Bean(name= "java") public Person person1(){ return new Person("java",12); } @Conditional(WindowsCondition.class) @Bean(name= "linux") public Person person2(){ return new Person("linux",22); } }
5.执行单元测试:
import com.example.test.entity.Person; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import java.util.Map; @SpringBootTest class TestApplicationTests { @Autowired private ApplicationContext applicationContext; @Test void contextLoads() { Map<String, Person> personBeanMap = applicationContext.getBeansOfType(Person.class); personBeanMap.forEach((beanName, beanValue) -> { System.out.println(beanName + "--" + beanValue); }); } }
运行之后只会打印 person1 这个bean 的信息。
四。@ConditionalOnProperty 注解的使用
该注解经常用来管理配置文件中的某些配置开关,比如 中间件 通过这个配置判断是否进行加载。
查看 @ConditionalOnProperty 注解源码
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Conditional; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional({OnPropertyCondition.class}) public @interface ConditionalOnProperty { String[] value() default {}; String prefix() default ""; String[] name() default {}; String havingValue() default ""; boolean matchIfMissing() default false; }
value : String数组 该属性与下面的 name 属性不可同时使用,当value所对应配置文件中的值为false时,注入不生效,不为fasle注入生效
prefix :配置文件中key的前缀,可与value 或 name 组合使用
name :与 value 作用一致
havingValue : 与value 或 name 组合使用,只有当value 或 name 对应的值与havingValue的值相同时,注入生效
matchIfMissing :该属性为true时,配置文件中缺少对应的value或name的对应的属性值,也会注入成功
使用示例:
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnProperty(prefix = "redis.config",value = "enabled",havingValue = "true") public class RedisConfiguration { }
在application.yml 配置文件配置:
redis.config.enabled=true
当 redis.config.enabled 值为 true时,会加载该类的配置,若只为false,则不加载。
通过这种方式,可以很好的控制一些功能在不同环境上的开发性和使用性。