Spring注解详解之组件注册(@Conditional)

Spring注解详解之组件注册(@Conditional)

@Conditional

定义

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

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	/**
	 * All {@link Condition Conditions} that must {@linkplain Condition#matches match}
	 * in order for the component to be registered.
	 */
	Class<? extends Condition>[] value();

}

从上面源码,该注解可以使用在方法和类上,并且只有一个value属性,该属性是继承了Condition接口的实现类的数组

@FunctionalInterface
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

使用在方法上

配置类,要求:根据运行环境系统不同注入不同的bean,Window系统中注入Bill,Linux系统中注入Linux

@Configuration
public class MyConfig2 {

    /*
     singleton:单例模式,默认配置,不指定的情况下都是单例的,IOC容器启动时创建bean,每次获取都是同一个对象
     prototype:多列,IOC容器启动不会创建对象,当调用该对象时才会创建对象,每次获取都是新的对象
     request:同一次请求创建一个实例
     session:同一个session创建一个实例
     */
//    @Scope("prototype")
//    @Lazy
    @Bean
    public Person person(){
        System.out.println("容器中创建person...");
        return new Person(111, "zhangsan");
    }
    //通过条件判断进行bean的注入
    @Conditional(WindowCondition.class)
    @Bean("Bill")
    public Person person01(){
        return new Person(222, "Bill Gates");
    }
    @Conditional(LinuxCondition.class)
    @Bean("Linux")
    public Person person02(){
        return new Person(222, "Linux");
    }

}

实现了Condition接口的两个自定义的实现类

public class WindowCondition implements Condition {
    /*
    ConditionContext:上下文环境
    AnnotatedTypeMetadata:当前标准@conditional注解类的注解信息
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取容器中bean定义类
        //BeanDefinitionRegistry registry = context.getRegistry();
        //判断容器中是否有person
        //boolean flag = registry.containsBeanDefinition("person");
        //if(flag){
        //    return true;
        //}
        Environment environment = context.getEnvironment();
        //获取系统信息,判断是否是window系统
        String property = environment.getProperty("os.name");
        if(property.contains("Window")){
            return true;
        }
        return false;
    }
}
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if(property.contains("Linux")){
            return true;
        }
        return false;
    }
}

测试方法

@Test
public void testAnno3(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
    //获取运行环境对象  
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    //通过环境对象获取系统信息
    String property = environment.getProperty("os.name");
    System.out.println(property);

    Map<String, Person> beans = applicationContext.getBeansOfType(Person.class);
    System.out.println(beans);
}
//输出结果,可见在window系统情况下,创建了Bill,没有Linux
容器中创建person...
Windows 10
{person=Person{id=111, name='zhangsan'}, Bill=Person{id=222, name='Bill Gates'}}

模拟Linux系统环境

在这里插入图片描述

再次执行上面的代码,输出结果中只有Linux

容器中创建person...
Linux
{person=Person{id=111, name='zhangsan'}, Linux=Person{id=222, name='Linux'}}

如果将上面WindowCondition中这部分代码放开,表示只有容器中有person对象,就会创建Bill,输出结果会包含Bill和Linux

在这里插入图片描述

使用在类上

@Configuration
@Conditional(WindowCondition.class)//将判断条件放在类上,表示如果该条件不符合,则类中的方法都不会执行
public class MyConfig2 {
    /*
     singleton:单例模式,默认配置,不指定的情况下都是单例的,IOC容器启动时创建bean,每次获取都是同一个对象
     prototype:多列,IOC容器启动不会创建对象,当调用该对象时才会创建对象,每次获取都是新的对象
     request:同一次请求创建一个实例
     session:同一个session创建一个实例
     */
//    @Scope("prototype")
//    @Lazy
    @Bean
    public Person person(){
        System.out.println("容器中创建person...");
        return new Person(111, "zhangsan");
    }

    @Bean("Bill")
    public Person person01(){
        return new Person(222, "Bill Gates");
    }
    @Conditional(LinuxCondition.class)
    @Bean("Linux")
    public Person person02(){
        return new Person(222, "Linux");
    }
}

测试方法,还是模拟Linux系统环境

@Test
public void testAnno3(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
    //获取运行环境对象  
    ConfigurableEnvironment environment = applicationContext.getEnvironment();
    //通过环境对象获取系统信息
    String property = environment.getProperty("os.name");
    System.out.println(property);

    Map<String, Person> beans = applicationContext.getBeansOfType(Person.class);
    System.out.println(beans);
    String[] names = applicationContext.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
}
//输出结果,可以看出配置类中的方法都没有执行,容器中的对象都是spring自己注入的
Linux
{}
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

多个条件的情况

由于该注解的value属性是一个数组,可以存着多个的情况,如果是多个的情况,该怎么判断

自定义一个condition,进行测试,

public class CustCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}
//对配置类进行改造
@Configuration
@Conditional({LinuxCondition.class, CustCondition.class})
public class MyConfig2 {...}

@Configuration
@Conditional({WindowCondition.class, CustCondition.class})
public class MyConfig2 {...}

对配置类进行改造进行验证结果,两个条件的情况下,是且的关系,只有都是true时,才会判断为真

CustCondition.class})
public class MyConfig2 {…}

@Configuration
@Conditional({WindowCondition.class, CustCondition.class})
public class MyConfig2 {…}

对配置类进行改造进行验证结果,两个条件的情况下,是且的关系,只有都是true时,才会判断为真

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值