@Autowired Spring @Component 和 @ConditionalOnProperty
@Autowired Spring @Component with @ConditionalOnProperty
我可以使用 @Autowired
Spring 4.x @Component
和 @ConditionalOnProperty
来选择 Feature[=35 的实现吗=] 基于 featuretoggles.properties 文件?
public class Controller {
@Autowired
private Feature feature;
}
@Component
@ConditionalOnProperty(name = "b", havingValue = "off")
public class A implements Feature {
}
@Component
@ConditionalOnProperty(name = "b", havingValue = "on")
public class B implements Feature {
}
@Configuration
@PropertySource("classpath:featuretoggles.properties")
public class SomeRandomConfig {
}
使用 src/main/resources/featuretoggles.properties 文件:
b = on
(切换的名称 "b" 和 class "B" 匹配的名称是巧合;我的目的不是让它们相等,切换可以有任何姓名。)
这无法在 Controller
中使用 UnsatisfiedDependencyException
自动连接 feature
,表示 "No qualifying bean of type 'Feature' available: expected at least 1 bean that qualifies as autowire candidate"。
我知道我可以通过 @Configuration
class 实现这一点,根据 属性 选择 @Bean
。但是,当我这样做时,每次添加功能切换时我都必须添加一个新的配置 class,并且这些配置 class 将非常相似:
@Configuration
@PropertySource("classpath:featuretoggles.properties")
public class FeatureConfig {
@Bean
@ConditionalOnProperty(name = "b", havingValue = "on")
public Feature useB() {
return new B();
}
@Bean
@ConditionalOnProperty(name = "b", havingValue = "off")
public Feature useA() {
return new A();
}
}
我按照 this guide 做了你想做的事。第一步是写一个 Condition
...
public class OnEnvironmentPropertyCondition implements Condition
{
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta)
{
Environment env = ctx.getEnvironment();
Map<String, Object> attr = meta.getAnnotationAttributes(
ConditionalOnEnvProperty.class.getName());
boolean shouldPropExist = (Boolean)attr.get("exists");
String prop = (String)attr.get("value");
boolean doesPropExist = env.getProperty(prop) != null;
// doesPropExist shouldPropExist result
// true true true
// true false false
// false true false
// true false true
return doesPropExist == shouldPropExist;
}
}
...然后是使用该条件的注释。
/*
* Condition returns true if myprop exists:
* @ConditionalOnEnvProperty("myprop")
*
* Condition returns true if myprop does not exist
* @ConditionalOnEnvProperty(value="myprop", exists=false)
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnEnvironmentPropertyCondition.class)
public @interface ConditionalOnEnvProperty
{
public String value();
public boolean exists() default true;
}
您可以使用 @PropertySource 注释将 featuretoggles.properties
添加到环境中。
我可以使用 @Autowired
Spring 4.x @Component
和 @ConditionalOnProperty
来选择 Feature[=35 的实现吗=] 基于 featuretoggles.properties 文件?
public class Controller {
@Autowired
private Feature feature;
}
@Component
@ConditionalOnProperty(name = "b", havingValue = "off")
public class A implements Feature {
}
@Component
@ConditionalOnProperty(name = "b", havingValue = "on")
public class B implements Feature {
}
@Configuration
@PropertySource("classpath:featuretoggles.properties")
public class SomeRandomConfig {
}
使用 src/main/resources/featuretoggles.properties 文件:
b = on
(切换的名称 "b" 和 class "B" 匹配的名称是巧合;我的目的不是让它们相等,切换可以有任何姓名。)
这无法在 Controller
中使用 UnsatisfiedDependencyException
自动连接 feature
,表示 "No qualifying bean of type 'Feature' available: expected at least 1 bean that qualifies as autowire candidate"。
我知道我可以通过 @Configuration
class 实现这一点,根据 属性 选择 @Bean
。但是,当我这样做时,每次添加功能切换时我都必须添加一个新的配置 class,并且这些配置 class 将非常相似:
@Configuration
@PropertySource("classpath:featuretoggles.properties")
public class FeatureConfig {
@Bean
@ConditionalOnProperty(name = "b", havingValue = "on")
public Feature useB() {
return new B();
}
@Bean
@ConditionalOnProperty(name = "b", havingValue = "off")
public Feature useA() {
return new A();
}
}
我按照 this guide 做了你想做的事。第一步是写一个 Condition
...
public class OnEnvironmentPropertyCondition implements Condition
{
@Override
public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta)
{
Environment env = ctx.getEnvironment();
Map<String, Object> attr = meta.getAnnotationAttributes(
ConditionalOnEnvProperty.class.getName());
boolean shouldPropExist = (Boolean)attr.get("exists");
String prop = (String)attr.get("value");
boolean doesPropExist = env.getProperty(prop) != null;
// doesPropExist shouldPropExist result
// true true true
// true false false
// false true false
// true false true
return doesPropExist == shouldPropExist;
}
}
...然后是使用该条件的注释。
/*
* Condition returns true if myprop exists:
* @ConditionalOnEnvProperty("myprop")
*
* Condition returns true if myprop does not exist
* @ConditionalOnEnvProperty(value="myprop", exists=false)
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnEnvironmentPropertyCondition.class)
public @interface ConditionalOnEnvProperty
{
public String value();
public boolean exists() default true;
}
您可以使用 @PropertySource 注释将 featuretoggles.properties
添加到环境中。