@Conditional 详细讲解和示例
一、@Conditional简介
在开发基于SpringBoot的项目时,经常看到下面的注解:
- ConditionalOnProperty
- ConditionalOnResource
- ConditionalOnBean
- ConditionalOnClass
- ConditionalOnMissingBean
- ConditionalOnMissingClass
虽然能大致上理解它们的用途,并且能简单使用,但是还是想更加深入的学习下这些条件装配注解。
看了B站尚硅谷雷丰阳老师的《Spring注解驱动教程》,简单整理如下笔记。
上面注解在定义时,都有 @ C o n d i t i o n a l \color{red}{@Conditional} @Conditional注解修饰,例如下面:
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {
//省略其它
}
@Conditional的定义:
@Target({
ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
- @ C o n d i t i o n a l \color{red}{@Conditional} @Conditional的作用是按照一定的条件进行判断,满足条件给容器注册Bean
- 从代码中可以看到,需要传入一个 C l a s s 数 组 \color{red}{Class数组} Class数组,并且需要继承Condition接口
- Condition是个 接 口 \color{red}{接口} 接口,需要实现matches方法,返回true则注入Bean,false则不注入
二、示例:加载2个Bean
1. 定义Person类
@Data
public class Person {
private String name;
private int age;
public Person(){
System.out.println("初始化:Person()");
}
public Person(String name, int age) {
System.out.println("初始化:Person(String name, int age)");
this.name = name;
this.age = age;
}
}
2. 利用@Configuration + @Bean加载2个Bean
利用@Configuration + @Bean加载2个Bean
@Configuration
public class MyBeanConfig {
@Bean
public Person person1(){
return new Person("Bill Gates", 66);
}
@Bean
public Person person2(){
return new Person("Linus", 50);
}
}
3. 测试是否都加载到Spring容器中
@SpringBootApplication
public class DictApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(DictApplication.class, args);
Map<String, Person> personMap = run.getBeansOfType(Person.class);
System.out.println(personMap);
}
}
结果如下:
{
person1=Person(name=Bill Gates, age=66), person2=Person(name=Linus, age=50)}
三、利用@Conditional根据条件加载Bean
1. 创建条件判断的类
如果是Windows系统则加载Bean
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
String property = env.getProperty("os.name");
if (property.contains("Windows")){
return true;
}
return false;
}
}
如果是Linux系统则加载Bean
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
String property = env.getProperty("os.name");
if (property.contains("Linux")){
return true;
}
return false;
}
}
2. @Conditional放在 方 法 上 \color{red}{方法上} 方法上
@Conditional放在方法上,只能决定该单个方法返回的实例是否加载到容器
@Configuration
public class MyBeanConfig {
@Bean
@Conditional(WindowsCondition.class)
public Person person1(){
return new Person("Bill Gates", 66);
}
@Bean
@Conditional(LinuxCondition.class)
public Person person2(){
return new Person("Linus", 50);
}
}
因为我这是Windows 10,所以返回如下:
{
person1=Person(name=Bill Gates, age=66)
3. @Conditional放在 类 上 \color{red}{类上} 类上
@Conditional放在类上,则可以判断该类下一组的Bean是否可以加载到Spring容器
@Configuration
@Conditional(WindowsCondition.class)
public class MyBeanConfig {
@Bean
//@Conditional(WindowsCondition.class)
public Person person1(){
return new Person("Bill Gates", 66);
}
@Bean
//@Conditional(LinuxCondition.class)
public Person person2(){
return new Person("Linus", 50);
}
}
因为我这是Windows 10,@Conditional(WindowsCondition.class)生效可用,所以返回如下:
{
person1=Person(name=Bill Gates, age=66), person2=Person(name=Linus, age=50)}
4. @Conditional传 多 个 \color{red}{多个} 多个条件,是 且 \color{red}{且} 且关系
@Conditional接受一个Class数组,可以传多个条件,当所有条件都是true时,才生效
可想项目的代码是不会加载Person对象的,因为
WindowsCondition.class返回 true,
LinuxCondition.class返回 false,
所以MyBeanConfig整个类失效,不能加载它下面的Bean。
@Configuration
@Conditional({
WindowsCondition.class, LinuxCondition.class})
public class MyBeanConfig {
@Bean
//@Conditional(WindowsCondition.class)
public Person person1(){
return new Person("Bill Gates", 66);
}
@Bean
//@Conditional(LinuxCondition.class)
public Person person2(){
return new Person("Linus", 50);
}
}