Springboot的版本2.0.5.release
先上代码吧,如下List-1
List-1
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中。
Condition是在什么地方被调用呢,在org.springframework.context.annotation.ConditionEvaluator中,如下List-2
List-2
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-3
List-3
<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来实现的,不过在实现上更为复杂。
(adsbygoogle = window.adsbygoogle || []).push({});