spring @Conditional的使用与扩展源码分析
作者:morris131
这篇文章主要介绍了spring @Conditional的使用与扩展,这里需要注意如果Condition返回的是false,那么spirng就不会对方法或类进行解析,具体源码分析跟随小编一起看看吧
@Conditional的使用
@Conditional可以根据条件来判断是否注入某些Bean。
package com.morris.spring.config; import com.morris.spring.condition.LinuxCondition; import com.morris.spring.condition.WindowsCondition; import com.morris.spring.entity.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class ConditionalConfig { // 如果是windows系统就注入bill @Conditional(WindowsCondition.class) @Bean(name = "user") public User bill() { return new User("bill", 22); } // 如果是linux系统就注入linus @Conditional(LinuxCondition.class) public User linus() { return new User("linus", 20); }
WindowsCondition和LinuxCondition都需要实现Condition接口。
WindowsCondition
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class WindowsCondition implements Condition { /** * 根据条件判断是否注入对应的Bean * @param conditionContext 应用上下文 * @param annotatedTypeMetadata 加了@Conditional注解的方法的元数据信息 * @return */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String osName = conditionContext.getEnvironment().getProperty("os.name"); if(osName.contains("Windows")) { return true; } return false; } }
LinuxCondition
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String osName = conditionContext.getEnvironment().getProperty("os.name"); if(osName.contains("linux")) { return true; } return false; } }
如果要测试LinuxCondition并不需要再linux系统下运行,只需要的启动时设置环境参数:-Dos.name=linux
。
Conditional的扩展
ConditionalOnBean
ConditionalOnBeanc.java
package com.morris.spring.condition; import org.springframework.context.annotation.Conditional; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnBeanCondition.class) public @interface ConditionalOnBean { Class<?>[] value() default {}; }
OnBeanCondition.java
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class OnBeanCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnBean.class.getName()); Class<?>[] clazz = (Class<?>[]) annotationAttributes.get("value"); for (Class<?> aClass : clazz) { Map<String, ?> beans = context.getBeanFactory().getBeansOfType(aClass); if(beans.isEmpty()) { return false; } } return true; } }
ConditionalOnProperty
ConditionalOnProperty.java
package com.morris.spring.condition; import org.springframework.context.annotation.Conditional; import java.lang.annotation.*; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Conditional(OnPropertyCondition.class) public @interface ConditionalOnProperty { String[] value() default {}; }
OnPropertyCondition.java
package com.morris.spring.condition; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class OnPropertyCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(ConditionalOnProperty.class.getName()); String[] propertyArray = (String[]) annotationAttributes.get("value"); for (String property : propertyArray) { if(!context.getEnvironment().containsProperty(property)) { return false; } } return true; } }
源码分析
如果Condition返回的是false,那么spirng就不会对方法或类进行解析。
org.springframework.context.annotation.ConditionEvaluator#shouldSkip
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) { // 判断类或方法上面是否有@Conditional注解 if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } if (phase == null) { if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); List<Condition> conditions = new ArrayList<>(); for (String[] conditionClasses : getConditionClasses(metadata)) { for (String conditionClass : conditionClasses) { Condition condition = getCondition(conditionClass, this.context.getClassLoader()); conditions.add(condition); AnnotationAwareOrderComparator.sort(conditions); for (Condition condition : conditions) { ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); // 调用condition.matches方法 if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) { return true; return false; }
到此这篇关于spring @Conditional的使用与扩展的文章就介绍到这了,更多相关spring @Conditional使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!