Springboot的版本2.0.5.releasejava
先上代码吧,以下List-1linux
List-1git
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class ConditionConfig { @Bean @Conditional(LinuxCondition.class) public OsService linuxOs(){ return new LinuxService(); } @Bean @Conditional(DefaultCondition.class) public OsService defaultOs(){ return new DefaultService(); } } public class DefaultCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { boolean defaultOs = !context.getEnvironment().getProperty("os.name").contains("Linux"); System.out.println("defaultOs:" + defaultOs); return defaultOs; } } public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { boolean linux = context.getEnvironment().getProperty("os.name").contains("Linux"); System.out.println("linux:" + linux); return linux; } } public class DefaultService implements OsService{ @Override public void printName() { System.out.println("Default"); } } public class LinuxService implements OsService{ @Override public void printName() { System.out.println("Linux"); } } public interface OsService { void printName(); } @EnableAutoConfiguration public class OsTest { public static void main(String[] args) { ConfigurableApplicationContext context = new SpringApplicationBuilder(ConditionConfig.class) .web(WebApplicationType.NONE) .run(args); OsService bean = context.getBean(OsService.class); bean.printName(); } }
Conditional注解很重要,是Springboot自动化配置的基础,它会根据指向的condition实现类,在SpringIOC的时候调用其matches方法,若是返回true则这个bean注册到beanFactory中。github
Condition是在什么地方被调用呢,在org.springframework.context.annotation.ConditionEvaluator中,以下List-2web
List-2spring
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) { 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(); } if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) { return true; } } return false; }
会查找全部Conditional注解的value值,以后实例化、排序,而后调用matches方法。我发现ConditionEvaluator.shouldSkip()被不少地方调用到,可是基本都是在BeanDefinitionReader等扫描的时候调用,以下List-3ide
List-3spring-boot
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } ...
Springboot中的ConditionalOnClass/ConditionalOnMissingClass等都是基本Spring的condition来实现的,不过在实现上更为复杂。ui