Spring注解@Conditional案例解析

 更新时间:2019年10月25日 09:12:16   作者:ねぇ  
这篇文章主要介绍了Spring注解@Conditional案例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

【1】@Conditional介绍

@Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean。

@Conditional源码:

//此注解可以标注在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) 
@Documented
public @interface Conditional {
  Class<? extends Condition>[] value();
}

从代码中可以看到,需要传入一个Class数组,并且需要继承Condition接口:

public interface Condition {
  boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}

Condition是个接口,需要实现matches方法,返回true则注入bean,false则不注入。

【2】@Conditional示例

首先,创建Person类:

public class Person {
 
  private String name;
  private Integer age;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public Integer getAge() {
    return age;
  }
 
  public void setAge(Integer age) {
    this.age = age;
  }
 
  public Person(String name, Integer age) {
    this.name = name;
    this.age = age;
  }
 
  @Override
  public String toString() {
    return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
  }
}

创建MyConfig类,用于配置两个Person实例并注入,一个是Bill Gates,一个是linus。

@Configuration
public class MyConfig {
 
  @Bean(name = "bill")
  public Person person1(){
    return new Person("Bill Gates",62);
  }
 
  @Bean("linus")
  public Person person2(){
    return new Person("Linus",48);
  }
}

写一个测试类,测试是否注入成功

public class ConditionalTest {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
 
  @Test
  public void test1(){
    Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
    System.out.println(map);
  }
}
/**测试结果
{bill=Person{name='Bill Gates',age=62},linus=Person{name='Linus',age='48'}}
*/

这是一个简单的例子,现在问题来了,如果我想根据当前操作系统来注入Person实例,windows下注入bill,linux下注入linus,怎么实现呢?

这就需要我们用到@Conditional注解了,前言中提到,需要实现Condition接口,并重写方法来自定义match规则。

首先,创建一个WindowsCondition类:

public class WindowsCondition implements Condition {
 
  /**
   * @param conditionContext:判断条件能使用的上下文环境
   * @param annotatedTypeMetadata:注解所在位置的注释信息
   * */
  @Override
  public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    //获取ioc使用的beanFactory
    ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
    //获取类加载器
    ClassLoader classLoader = conditionContext.getClassLoader();
    //获取当前环境信息
    Environment environment = conditionContext.getEnvironment();
    //获取bean定义的注册类
    BeanDefinitionRegistry registry = conditionContext.getRegistry();
 
    //获得当前系统名
    String property = environment.getProperty("os.name");
    //包含Windows则说明是windows系统,返回true
    if (property.contains("Windows")){
      return true;
    }
    return false;
  }
}

接着,创建LinuxCondition类:

public class LinuxCondition 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;
  }
}

修改MyConfig:

@Configuration
public class MyConfig { 
  //只有一个类时,大括号可以省略
  //如果WindowsCondition的实现方法返回true,则注入这个bean  
  @Conditional({WindowsCondition.class})
  @Bean(name = "bill")
  public Person person1(){
    return new Person("Bill Gates",62);
  }
  //如果LinuxCondition的实现方法返回true,则注入这个bean
  @Conditional({LinuxCondition.class})
  @Bean("linus")
  public Person person2(){
    return new Person("Linus",48);
  }
}

标注在方法上:

​ 修改测试程序,开始测试:

public class ConditionalTest {
  AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
 
  @Test
  public void test1(){
    String osName = applicationContext.getEnvironment().getProperty("os.name");
    System.out.println("当前系统为:" + osName);
    Map<String, Person> map = applicationContext.getBeansOfType(Person.class);
    System.out.println(map);
  }
}
/**测试结果
当前系统为:Windows 10
{bill=Person{name='Bill Gates',age=62}}
*/

一个方法只能注入一个bean实例,所以@Conditional标注在方法上只能控制一个bean实例是否注入

标注在类上:

@Configuration
@Conditional({WindowsCondition.class})
public class MyConfig {
 
  //只有一个类时,大括号可以省略
  //如果WindowsCondition的实现方法返回true,则注入这个bean  
  @Bean(name = "bill")
  public Person person1(){
    return new Person("Bill Gates",62);
  }
 
  //如果LinuxCondition的实现方法返回true,则注入这个bean
  @Bean("linus")
  public Person person2(){
    return new Person("Linus",48);
  }
}

一个类中可以注入很多实例,@Conditional标注在类上就决定了一批bean是否注入。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Spring Boot 中的静态资源放置位置

    Spring Boot 中的静态资源放置位置

    这篇文章主要介绍了Spring Boot 中的静态资源到底要存放哪里,很多童鞋对这个问题很纠结,接下来通过本文给大家介绍下,需要的朋友可以参考下
    2019-04-04
  • Spring Boot中使用Spring-Retry重试框架的实现

    Spring Boot中使用Spring-Retry重试框架的实现

    本文主要介绍了Spring Boot中使用Spring-Retry重试框架的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • Java通过底层原码了解数组拷贝

    Java通过底层原码了解数组拷贝

    一般说起数组的拷贝,首先想到的就是用循环对数组进行拷贝。但其实JAVA为我们提供了一些拷贝数组比较方便的方法,有完全拷贝的方法,也有部分拷贝的方法。接下来就一一介绍这些方法
    2022-07-07
  • Spring boot事务无效报错:Transaction not enabled问题排查解决

    Spring boot事务无效报错:Transaction not enabled问题排查解决

    在业务代码中经常需要保证事务的原子性,但是有的时候确实是出现事务没有生效,这篇文章主要给大家介绍了关于Spring boot事务无效报错:Transaction not enabled问题排查的相关资料,需要的朋友可以参考下
    2023-11-11
  • SPRINGBOOT读取PROPERTIES配置文件数据过程详解

    SPRINGBOOT读取PROPERTIES配置文件数据过程详解

    这篇文章主要介绍了SPRINGBOOT读取PROPERTIES配置文件数据过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Mybatis ResultMap和分页操作示例详解

    Mybatis ResultMap和分页操作示例详解

    这篇文章主要为大家介绍了Mybatis ResultMap和分页操作示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • java同步器AQS架构AbstractQueuedSynchronizer原理解析

    java同步器AQS架构AbstractQueuedSynchronizer原理解析

    这篇文章主要为大家介绍了java同步器AQS架构AbstractQueuedSynchronizer的底层原理及源码解析,有需要的朋友可以借鉴参考下,希望能有所帮助,祝大家多多进步早日升职加薪
    2022-03-03
  • Springboot 多租户SaaS搭建方案

    Springboot 多租户SaaS搭建方案

    这篇文章主要介绍了Springboot 多租户SaaS方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • 一文搞懂JMeter engine中HashTree的配置问题

    一文搞懂JMeter engine中HashTree的配置问题

    本文主要介绍了JMeter engine中HashTree的配置,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Java中的RMI使用方法详解

    Java中的RMI使用方法详解

    这篇文章主要介绍了Java中的RMI使用方法,RMI是Java提供的一个完善的简单易用的远程方法调用框架,采用客户服务器通信方式,在服务器上部署了提供各种服务的远程对象,下面我们来详细讲解
    2023-10-10

最新评论