2017-01-28 30 views
2

我正在使用Spring Boot 1.4.3 @AutoConfiguration其中我根据用户指定的属性自动创建bean。用户可以指定一系列的服务,在需要版本字段:如果用户忘记对哪怕只是一个服务指定必填字段@ConditionalOnProperty列表或数组?

service[0].name=myServiceA 
service[0].version=1.0 

service[1].name=myServiceB 
service[1].version=1.2 

... 

,我想回退,而不是创建任何bean。我可以用@ConditionalOnProperty完成这个吗?我想要类似于:

@Configuration 
@ConditionalOnProperty({"service[i].name", "service[i].version"}) 
class AutoConfigureServices { 
.... 
} 
+1

我不认为* *这是有效的本身 - 但如果你是在构造函数中设置这些值,你可以得到一个抛出异常(在构造函数中显式地或在Spring检查是否存在时隐式地)。 – chrylis

+0

这是一个好主意。如果构造函数在实例化任何bean之前在自动配置类上运行,也许我可以以某种方式阻止创建bean?不幸的是,我不能抛出异常,因为忘记道具不应该是致命的。 – Strumbles

+0

为什么不呢?你有一个半配置的bean。 – chrylis

回答

0

这是我创建的自定义Condition。它需要一些抛光是更通用的(即不硬编码的字符串),但对我很好。

使用,我注解我的配置类@Conditional(RequiredRepeatablePropertiesCondition.class)

public class RequiredRepeatablePropertiesCondition extends SpringBootCondition { 

    private static final Logger LOGGER = LoggerFactory.getLogger(RequiredRepeatablePropertiesCondition.class.getName()); 

    public static final String[] REQUIRED_KEYS = { 
      "my.services[i].version", 
      "my.services[i].name" 
    }; 

    @Override 
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { 
     List<String> missingProperties = new ArrayList<>(); 
     RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(context.getEnvironment()); 
     Map<String, Object> services = resolver.getSubProperties("my.services"); 
     if (services.size() == 0) { 
      missingProperties.addAll(Arrays.asList(REQUIRED_KEYS)); 
      return getConditionOutcome(missingProperties); 
     } 
     //gather indexes to check: [0], [1], [3], etc 
     Pattern p = Pattern.compile("\\[(\\d+)\\]"); 
     Set<String> uniqueIndexes = new HashSet<String>(); 
     for (String key : services.keySet()) { 
      Matcher m = p.matcher(key); 
      if (m.find()) { 
       uniqueIndexes.add(m.group(1)); 
      } 
     } 
     //loop each index and check required props 
     uniqueIndexes.forEach(index -> { 
      for (String genericKey : REQUIRED_KEYS) { 
       String multiServiceKey = genericKey.replace("[i]", "[" + index + "]"); 
       if (!resolver.containsProperty(multiServiceKey)) { 
        missingProperties.add(multiServiceKey); 
       } 
      } 
     }); 
     return getConditionOutcome(missingProperties); 
    } 

    private ConditionOutcome getConditionOutcome(List<String> missingProperties) { 
     if (missingProperties.isEmpty()) { 
      return ConditionOutcome.match(ConditionMessage.forCondition(RequiredRepeatablePropertiesCondition.class.getCanonicalName()) 
        .found("property", "properties") 
        .items(Arrays.asList(REQUIRED_KEYS))); 
     } 
     return ConditionOutcome.noMatch(
       ConditionMessage.forCondition(RequiredRepeatablePropertiesCondition.class.getCanonicalName()) 
      .didNotFind("property", "properties") 
      .items(missingProperties) 
     ); 
    } 
}