一、@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);
    }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐