在进行spring进行开发时,当某个接口有多种实现方式并且我们只想让一种生效时,比如声明如下一个接口和两个实现:
public interface LanggageService { String say(); } public class ChineseServiceImpl implements LanggageService { @Override public String say() { return "你好"; } } public class EnglishServiceImpl implements LanggageService { @Override public String say() { return "hello"; } }
我们通常使用xml为某个接口配置实现类;
<bean id="languageService" class="com.liam.service.ChineseServiceImpl"></bean>
当然后来我们习惯使用注解的方式了,比如
@Bean public LanggageService englishService(){ return new EnglishServiceImpl(); }
当然也可以通过@Component进行扫描注入,这也是为了去除java令人发指的诸多xml配置的一项进步,所以当使用spring boot进行开发时,我们尽量摒弃了诸多配置,不管是Hibernate,JPA亦或者是mybatis...
但是也显然,有时候我们需要通过配置来选择我们使用的bean,基于xml还好,但是基于注解的话通过重新编译打包显然是不能接受的。。比如测试环境我们设置的数据源是mysql,生产环境换成oracle了,当然我们通常使用的是profile进行配置,但还是不够灵活,我们需要更细粒度的管理bean..所以也就有了Conditional。。。(废话连篇。。。)
比如我们在spring boot中要通过application.properties中进行配置来选择我们使用的bean
say.method=chinese
则可以声明两个Condition
public class SayChineseCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String m= conditionContext.getEnvironment().getProperty("say.method").toString(); boolean isChi= "chinese".equals(m); System.err.println("current chinese "+ isChi); return isChi; } } public class SayEnglishCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String m= conditionContext.getEnvironment().getProperty("say.method").toString(); boolean isEn= "english"==m; System.err.println("current english "+ isEn); return isEn; } }
然后实现类中配置上对应的Conditional:
@Service @Conditional(SayChineseCondition.class) public class ChineseServiceImpl implements LanggageService { @Override public String say() { return "你好"; } }
简单,灵活。
此处需要注意的是application.properties在spring boot中属于环境变量级别的配置加载,所以优先级较高,假如通过其他配置文件进行加载时借助PropertySource或者ConfigurationProperties之类的是不能如愿的,因为加载Condition时,我们的配置bean尚未加载,比如下面的方式是无效的。
@PropertySource(value = "first.properties") public class SayEnglishCondition implements Condition { @Value("${say.method}") private String lang; public String getLang() { return lang; } public void setLang(String lang) { this.lang = lang; } @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { String m=lang;// conditionContext.getEnvironment().getProperty("say.method").toString(); boolean isEn= "english".equals(m); System.err.println("current english "+ isEn); return isEn; } }
所以。。我们只能手动加载了。。
public class SayEnglishCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Properties properties = new Properties(); try { properties.load(conditionContext.getResourceLoader().getResource("first.properties").getInputStream()); } catch (IOException ex) { ex.printStackTrace(); } boolean isEn = "english".equals(properties.getProperty("say.method")); System.err.println("current english " + isEn); return isEn; } }