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时,才会判断为真