Spring提供了很多Condition给我们用,@ConditionalOnSingleCandidate表示当指定Bean在容器中只有一个,或者虽然有多个但是指定首选Bean,这个组合了@Conditional元注解,只是使用了不同的条件(Conditional)

详细参考:
@Conditional,满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的。
例子:
首先,两个Condition,判断当前系统是否是Windows或者Linux(True False)

public class LinuxCondition implements Condition {

    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
        return arg0.getEnvironment().getProperty("os.name").contains("Linux");
    }

}
public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
        return arg0.getEnvironment().getProperty("os.name").contains("Windows");
    }

}

然后,2个ListService实现类,表明不同系统下的ListService实现。

public interface ListService {
    public String showListCmd();
}
public class LinuxListService implements ListService{
    @Override
    public String showListCmd() {
        return "ls";
    }    
}
public class WindowsListService implements ListService{
    @Override
    public String showListCmd() {
        return "dir";
    }    
}

然后ConditionConfig使用了Java配置与@Conditional注解,根据LinuxCondition,或者WindowsCondition作为判断条件

@Configuration
public class ConditionConfig {

    @Bean
    @Conditional(WindowsCondition.class)
    public ListService windowsListService() {
        return new WindowsListService();
    }

    @Bean
    @Conditional(LinuxCondition.class)
    public ListService linuxListService() {
        return new LinuxListService();
    }

}

最后,App.java 测试成功。

public class App {
    public static void main(String[] args) {

        ApplicationContext context = new AnnotationConfigApplicationContext(
                ConditionConfig.class);

        ListService ls = context.getBean(ListService.class);
        System.out.println(context.getEnvironment().getProperty("os.name")
                + "系统下的列表命令为:" + ls.showListCmd());
    }
}