@Conditional
注解是spring在4.0版本提供的一个注解,作用是贴有这个注解或间接贴有的bean在满足指定的Condition
接口实现类的matches
方法校验之后,才注册这个bean。关于@Conditional
注解的实现原理,可以看看前面写的一篇文章。@Conditional注解的解析。
1. 直接使用@Conditional
注解
1.1 定义一个Bean,并在上面贴上@Conditional
注解
public class ConditionalTestBootstrap {
@Bean
@Conditional(MyCondition.class)
public String conditionTest(){
return "condition test";
}
}
如上面的代码所示,直接使用@Conditional
注解的方式。使用这个注解的前提要求是:这个对象需要是一个被容器管理的对象。
1.2 @Conditional
注解指定的类实现Condition
接口
上面的@Conditional
注解中指定的类是MyCondition
。因此这个类需要实现Condition
接口
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Map attributes = annotatedTypeMetadata.getAnnotationAttributes(Conditional.class.getName());
Object value = attributes.get("value");
if (value!=null){
System.out.println("当校验条件为true的时候,返回true");
return true;
}else {
System.out.println("当校验条件为false的时候,返回false");
return false;
}
}
}
在实现的matches
方法中,可以自行定义判断逻辑,从AnnotatedTypeMetadata
中可以获取贴有注解信息的对象或者方法的很多信息,可以利用这些信息来进行逻辑判断。
当最终结果返回为true的时候,就表示校验符合,就会将bean进行注册。
1.3 在启动类中进行校验
public class ConditionalTestBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ConditionalTestBootstrap .class)
.web(WebApplicationType.NONE)
.run(args);
String conditionTest = applicationContext.getBean("conditionTest", String.class);
System.out.println("conditionTest Bean "+conditionTest);
//关闭上下文
applicationContext.close();
}
}
最终的运行结果为conditionTest Bean condition test
。此时说明这个bean成功的被注入到了容器之中。
当我们把上面实现的matches
方法中返回的结果改为false的时候再试试
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return false;
}
}
此时运行结果为
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'conditionTest' available
at
......
最后运行出错了,因为容器中没有名称为conditionTest
的bean
2. 间接使用@Conditional
注解
因为spring原生提供的@Conditional
注解内部只有一个value属性用来指定我们匹配规则的类,没有其余的属性供我们使用。所以通常都是对@Conditional
注解进行派生使用。
2.1 定义一个@Conditional
注解的派生注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnSystemPropertyCondition.class)
public @interface ConditionalOnSystemProperty {
/**
* java 系统属性名称
* @return
*/
String name() default "";
/**
* java系统属性值
* @return
*/
String value() default "";
}
定义@Conditional
的派生注解,通常是在自定义的注解上加上一个@Conditional
注解并指定实现匹配规则的Condition
接口的实现类。
2.2 实现Condition
接口处理
public class OnSystemPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map attributes = metadata.getAnnotationAttributes(ConditionalOnSystemProperty.class.getName());
String propertyName = String.valueOf(attributes.get("name"));
String propertyValue = String.valueOf(attributes.get("value"));
String javaProperty = System.getProperty(propertyName);
return propertyValue.equals(javaProperty);
}
}
上面就是自定义的判定逻辑。从AnnotatedTypeMetadata
中获取ConditionalOnSystemProperty
类型的注解,然后获取到注解内的属性值。然后比较来决定匹配结果。
2.3 在bean上面使用自定义的注解
public class ConditionalOnSystemPropertyBootstrap {
@Bean
@ConditionalOnSystemProperty(name = "user.name",value = "Administrator")
public String helloWorld(){
return "hello world szh";
}
}
在定义的bean上面加上自定义的@ConditionalOnSystemProperty
注解,并添加上对应的条件。
2.4 在启动类中校验
public class ConditionalOnSystemPropertyBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(ConditionalOnSystemPropertyBootstrap.class)
.web(WebApplicationType.NONE)
.run(args);
String helloWorld = applicationContext.getBean("helloWorld", String.class);
System.out.println("helloWorld Bean "+helloWorld);
//关闭上下文
applicationContext.close();
}
}
最后的运行结果为helloWorld Bean hello world szh
。说明我们的bean成功的注入到了容器中。到这里@Conditional
注解以及Condition
接口的扩展就完了。