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