通过条件注解@Conditional细粒度的选择bean实例

在进行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;
    }
}
原文地址:https://www.cnblogs.com/ylsforever/p/8047953.html