- 这个注解是Spring4新提供的,它的作用是按照一定的条件进行判断,满足条件给容器注册bean
-
在SpringBoot底层大量使用到,所有很重要(因为实际项目中有用到@ConditionalOnProperty这个注解)
image.png
现在还是来说说这个注解的一些定义和具体使用,对于SpringBoot中的使用,后期我会逐步慢慢学习
一、接口定义
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
/**
* All {@link Condition}s that must {@linkplain Condition#matches match}
* in order for the component to be registered.
*/
Class<? extends Condition>[] value();
}
根据定义可以知道以下几点:
- 此注解用到类和方法上
- 注解的值是一个Class数组,且Class必须继承Condition接口实现matches方法,matches方法返回值是boolean,true表示注入bean,false表示不注入bean
public interface Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
2、简单的demo
eg:注册两个Person,一个bill,一个linus,默认情况下这两个人一定都在容器中,涉及到一个Person类,一个配置类,一个测试用例
- Person类
@Data
@Component
@AllArgsConstructor
public class Person {
private String name;
private Integer age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
- 配置类()
@Configurable
//@ComponentScan(value = "com.test",excludeFilters ={@Filter(type = FilterType.CUSTOM,value = MyTypeFilter.class)})
public class Config {
@Bean
public Person person(){
return new Person();
}
@Bean("bill")
public Person person1(){
return new Person("Bill Gates",62);
}
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
}
- 测试用例获取容器中所有的bean
@org.junit.Test
public void testComponentScan() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
}
-
结果(可以看到不加任何条件的情况下,bill和linus这两个bean都加入到容器中了)
image.png
- 要求,如果当前系统是windows系统(WindowsCondition)就注册bill,如果是Linux系统(LinuxCondition)就注册linus
- LinuxCondition.class
//判断是否linux系统
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:注释信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系统
//1、能获取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、获取类加载器
ClassLoader classLoader = context.getClassLoader();
//3、获取当前环境信息
Environment environment = context.getEnvironment();
//4、获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
//可以判断容器中的bean注册情况,也可以给容器中注册bean
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
- WindowsCondition.class
//判断是否windows系统
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")){
return true;
}
return false;
}
}
- 修改配置类
在bill的bean上加上注解@Conditional(value = WindowsCondition.class)
在linus的bean上加上注解@Conditional(value = LinuxCondition.class)
@Conditional(value = WindowsCondition.class)
@Bean("bill")
public Person person1(){
return new Person("Bill Gates",62);
}
@Conditional(value = LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
-
运行结果(Windows系统运行的,所以只注册了lill)
image.png
-
运行Linux系统的结果(不能运行在Linux系统下,可以通过修改运行时参数)
这里写的是-Doa.name=linux这个linux是小写的,因为我在LinuxCondition.class的添加写的是linux
修改参数模拟Linux系统下

注意
1、上面记录的是将注解标注在方法上的,当然也可以标注到类上,如果将@Conditional(value = WindowsCondition.class)标注到类上,Windows环境下,bill和linus以及其他所有的bean都会被注入到容器中,linux环境下,这个配置类中的所有bean都不会被注入
2、@Conditional里面可以加入多个条件类,加入多个条件的结论是:
所有条件都必须为true才能注入容器中,只要一个条件为false,则不能注入
网友评论