Spring使用@Conditional进行条件装配的实现
作者:曹朋羽
在spring中有些bean需要满足某些环境条件才创建某个bean,这个时候可以在bean定义上使用@Conditional注解来修饰。@Conditional需要指定一个条件类,这个类不需实现Condition接口并且实现其matches方法。只有当matches方法返回true时才创建当前bean。
例如下面定义一个bean只有当当前jdk版本大于等于8时才创建该bean。
bean定义这里写的很简单,
@Service @Conditional(Java8Condition.class) public class ConditionService { }
看Java8Condition条件类
public class Java8Condition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.EIGHT); } }
这里判断当前java的版本,如果大于等于8则返回true,ConditionService会被创建成bean,否则不会创建该bean。
Condition的matches方法有两个入参,context和metadata。从context可以获取beanFactory和environment信息,从metadata可以获取当前bean上所有注解配置信息。通过这两个参数可以获取到很多信息了,这里就可以根据上下文来进行判断。不如beanFacotry是否有某个bean,当前环境的profile信息,某个属性的配置信息等等。
看到这里你是否想到了些什么,没错就是springboot的自动条件装配。springboot对@Conditional进行了扩展,在org.springframework.boot.autoconfigure.condition包下有很多封装好的条件注解。如
ConditionalOnBean:某个bean存在时
ConditionalOnClass: 某个class存在时
ConditionalOnExpression: SpEL表达式成立时
ConditionalOnJava: java环境版本
ConditionalOnProperty: 某个property值是多少时
ConditionalOnMissingBean: 某个bean不存在时
等等还有很多。这就明白为什么有些bean我们没有显示声明可以直接拿来注入使用了吧。
condition的扩展
虽然springboot也封装了很多场景的condition注解,但是难免有时候还是有些业务场景可能需要自定义conditon。这里就来以判断上下文某个属性值来扩展condition。
最开始看到@Conditional注解是只有一个Condition类来指定出来条件判断逻辑,没有额外的配置项。这里要判断某个property必须要指定property的key和value,所以第一步先自定义一个注解
@Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.METHOD }) @Conditional(PropertyConditionMatcher.class) public @interface MyPropertyCondition { String name(); String value(); }
这里自定义注解PropertyConditionMatcher两个属性name用来指定property的key,value用来指定property的value。除此之外我们自定义的注解还用@Conditional来修饰,这样才能我们自定义的注解才能被当作@Conditional来处理。然后来看我们的condition处理类PropertyConditionMatcher。
public class PropertyConditionMatcher implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(MyPropertyCondition.class.getName()); String propName = (String) annotationAttributes.get("name"); Object value = annotationAttributes.get("value"); String property = context.getEnvironment().getProperty(propName); if(property != null && property.equals(value)){ return true; } return false; } }
这里还是实现了Condition接口。然后首先从metadata中获取配置的property名称和value,然后从context的Environment根据前面的property名获取当前环境对应值,两个value进行对比相等来判断是否满足条件。
然后具体条件bean上配置MyPropertyCondition。
@Service @MyPropertyCondition(name = "condation.enable",value = "true") public class ConditionService { }
这样当我们在properties文件中配置condation.enable=true时,ConditionService就会创建为一个bean,否则不会创建。
以上就是Spring使用@Conditional进行条件装配的实现的详细内容,更多关于Spring @Conditional条件装配的资料请关注脚本之家其它相关文章!