今天给大家说一下springboot中@Conditional注解的作用。

在我们常用的声明一个配置类时,我们都会采用注解的方法,@Configuration@Bean一起搭配使用,@Configuration是指明当前类是一个配置类,就是代替之前的spring配置文件,在配置文件中用_<bean><bean/>_标签添加组件,但是现在有注解

@Bean:就是将方法的返回值添加到容器中,容器中的这个组件默认的id就是方法名

当我们再了解springboot自动装配的源码中,我们会发现有很多的组件,springboot在启动时会去加载,会发现在META-INF下会有spring.factories的配置,而且在配置时会从properties类中获取属性,我们可以在配置文件中指定这些属性的值。但是在用注解时,我们可以指定满足什么条件才会向容器中添加组件@Configuration。就是我们下面要扩展的。

Condition是一个接口,接口中有一个matches方法,返回值类型是boolean类型.今天我们只说@Conditional的使用,其他的都是一样的。

@Conditional详解 - 图1

详解

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。
@Conditional详解 - 图2
参数是Condition类的集合看看Condition接口
@Conditional详解 - 图3

matches就像正则的那个类一样…应该是true注入,false不注入

测试

下面用代码举例子说明一下,首先定义一个实体类

  1. @Data
  2. @AllArgsConstructor
  3. public class Person {
  4. private String name;
  5. private int age;
  6. }

我们可以自定义一个类实现Condition接口。创建两个类LinuxCondition,WindowsCondition分别实现Condition接口,作为@Contional注解的值;

  1. import org.springframework.context.annotation.Condition;
  2. import org.springframework.context.annotation.ConditionContext;
  3. import org.springframework.core.env.Environment;
  4. import org.springframework.core.type.AnnotatedTypeMetadata;
  5. public class LinuxCondition implements Condition {
  6. @Override
  7. public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
  8. Environment environment = conditionContext.getEnvironment();
  9. String property = environment.getProperty("os.name");
  10. if (property.contains("Linux")){
  11. return true;
  12. }
  13. return false;
  14. }
  15. }
  1. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  2. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  3. import org.springframework.context.annotation.Condition;
  4. import org.springframework.context.annotation.ConditionContext;
  5. import org.springframework.core.env.Environment;
  6. import org.springframework.core.type.AnnotatedTypeMetadata;
  7. public class WindowsCondition implements Condition {
  8. /**
  9. * @param conditionContext:判断条件能使用的上下文环境
  10. * @param annotatedTypeMetadata:注解所在位置的注释信息
  11. * */
  12. @Override
  13. public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
  14. //获取ioc使用的beanFactory
  15. ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
  16. //获取类加载器
  17. ClassLoader classLoader = conditionContext.getClassLoader();
  18. //获取当前环境信息
  19. Environment environment = conditionContext.getEnvironment();
  20. //获取bean定义的注册类
  21. BeanDefinitionRegistry registry = conditionContext.getRegistry();
  22. //获得当前系统名
  23. String property = environment.getProperty("os.name");
  24. //包含Windows则说明是windows系统,返回true
  25. if (property.contains("Windows")){
  26. return true;
  27. }
  28. return false;
  29. }
  30. }

接下来写一个配置,配置类记得要扫到

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Conditional;
  3. import org.springframework.context.annotation.Configuration;
  4. @Configuration
  5. public class PersonConfigure {
  6. @Bean(name = "bill")
  7. @Conditional({WindowsCondition.class})
  8. public Person person1() {
  9. return new Person("Bill Gates", 62);
  10. }
  11. @Bean("linus")
  12. @Conditional({LinuxCondition.class})
  13. public Person person2() {
  14. return new Person("Linus", 48);
  15. }
  16. }

然后测试一波,我这是springboot项目,测试比较简单.
@Conditional详解 - 图4

  1. import com.alibaba.fastjson.JSON;
  2. import com.ql.servicetest.conditionDemo.Person;
  3. import org.junit.Test;
  4. import org.springframework.beans.BeansException;
  5. import org.springframework.context.ApplicationContext;
  6. import org.springframework.context.ApplicationContextAware;
  7. import java.util.Map;
  8. public class ConditionTest extends BaseTest implements ApplicationContextAware {
  9. @Test
  10. public void test1() {
  11. Map<String, Person> beansOfType = ApplicationContext.getBeansOfType(Person.class);
  12. String property = ApplicationContext.getEnvironment().getProperty("os.name");
  13. System.out.println("当前系统为:"+property);
  14. System.out.println(JSON.toJSONString(beansOfType));
  15. }
  16. public ApplicationContext ApplicationContext;
  17. @Override
  18. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  19. this.ApplicationContext = applicationContext;
  20. }
  21. }

我直接继承baseTest测试类,然后实现ApplicationContextAware得到spring容器,简单方便。一开始不加Conditional注解,就是两个都有。

这两个类其实就是拿到当前运行环境进行判断,然后返回true,false。分别将 @Conditional注解加上,然后运行:
@Conditional详解 - 图5
发现只注入了gatesPerson类,然后将运行环境改为linux,试一波
@Conditional详解 - 图6
结果:
@Conditional详解 - 图7
@Conditional注解也可以加在注解上,加在注解上效果也是一样的,

如果多个条件呢?总结就是都返回true才会注入.
@Conditional详解 - 图8

思考

如果我类上返回true,方法上返回false呢? 如果我类上放回false,方法上返回true呢?

我猜想是如果类上返回了false,那就都不注入,不看你方法上的了,如果类上返回了true,才会判断方法上的,试一波

第一种,类上为True,
@Conditional详解 - 图9
返回
@Conditional详解 - 图10
第二种,类上为False
@Conditional详解 - 图11
猜想正确,

会先判断类上,如果类上不满足就直接不加载
如果类上满足还好判断方法上满足不满足.

源码

https://github.com/stackXu/study-authconfigure
@Conditional详解 - 图12