SpEL @ConditionalOnProperty 字符串属性为空或null

17

我目前在应用程序的yaml文件中使用String属性时,遇到了创建dataSource bean的问题。

理想情况下,我只想在应用程序的yaml文件中设置url时才创建dataSource bean。如果不存在(为空或null),则不应该创建bean。我知道这个条件检查的是布尔值,但有没有办法检查字符串属性是否为空或null?

DatabaseConfig.java

@Configuration
public class DatabaseConfig {
    @Value("${database.url:}")
    private String databaseUrl;

    @Value("${database.username:}")
    private String databaseUsername;

    @Value("${database.password:}")
    private String databasePassword;

    protected static final String DRIVER_CLASS_NAME = "com.sybase.jdbc4.jdbc.SybDriver";


    /**
     * Configures and returns a datasource. Optional
     *
     * @return A datasource.
     */
    @ConditionalOnProperty(value = "database.url")
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
            .url(testDatabaseUrl)
            .username(testDatabaseUsername)
            .password(testDatabasePassword)
            .build();
    }
}

application.yml(此字段将是可选的)

database:
  url: http://localhost:9000

@ConditionalOnProperty 已经有一个 matchIfMissing 参数,用于控制当属性不存在时会发生什么。您是否想说空字符串值在您的代码中是不存在的同义词? - Andy Brown
4个回答

27

您可以使用@ConditionalOnExpression,并将Spring表达式语言(SpEL)表达式作为值:

@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${database.url:}')")
@Bean
public DataSource dataSource() {
    // snip
}

为了更好的可读性和可重用性,您可以将其转换为注释:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${database.url:}')")
public @interface ConditionalOnDatabaseUrl {
}

@ConditionalOnDatabaseUrl
@Bean
public DataSource dataSource() {
    // snip
}

我可以知道为什么我们需要在那里使用泛型类型吗? T(org.springframework.util.StringUtils) - Hong
2
@Hong,T(..) 是用于引用类型的,与泛型无关。我猜你可能想到了 <T>。这是 SpEL 的参考文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions-types - sfussenegger

18

我遇到了同样的问题。据我所理解,你正在寻找“属性存在且不为空”的条件。这个条件没有现成的解决方案,因此需要编写一些代码。使用org.springframework.context.annotation.Conditional的解决方案对我有用:

  1. 创建如下ConditionalOnPropertyNotEmpty注释和相应的OnPropertyNotEmptyCondition类:

  2.  // ConditionalOnPropertyNotEmpty.java
    
     import org.springframework.context.annotation.Condition;
     import org.springframework.context.annotation.ConditionContext;
     import org.springframework.context.annotation.Conditional;
     import org.springframework.core.type.AnnotatedTypeMetadata;
     import java.lang.annotation.ElementType;
     import java.lang.annotation.Retention;
     import java.lang.annotation.RetentionPolicy;
     import java.lang.annotation.Target;
     import java.util.Map;
    
     @Target({ ElementType.TYPE, ElementType.METHOD })
     @Retention(RetentionPolicy.RUNTIME)
     @Conditional(ConditionalOnPropertyNotEmpty.OnPropertyNotEmptyCondition.class)
     public @interface ConditionalOnPropertyNotEmpty {
         String value();
    
         class OnPropertyNotEmptyCondition implements Condition {
    
             @Override
             public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
                 Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnPropertyNotEmpty.class.getName());
                 if (attrs == null) {
                     return false;
                 }
                 String propertyName = (String) attrs.get("value");
                 String val = context.getEnvironment().getProperty(propertyName);
                 return val != null && !val.trim().isEmpty();
             }
         }
     }
    
  3. 使用ConditionalOnPropertyNotEmpty注释您的bean,例如:

     @ConditionalOnPropertyNotEmpty("database.url")
     @Bean
     public DataSource dataSource() { ... }
    

--

或者,您可以将 detabase.url 显式地设置为 false(例如:detabase.url: false),或者在配置中根本不定义 detabase.url。然后,@ConditionalOnProperty(value = "database.url") 将按预期工作。


1
你可以尝试使用适用于Spring Core的更通用的注释:org.springframework.context.annotation.Conditional
在回调的上下文对象中,您可以获得所需的所有信息:org.springframework.context.annotation.Condition
另外,您可以考虑使用配置文件。

1

上面的主要答案是正确的,但由于 isEmpty 已被弃用,如果你(可能)已经加载了 apache commons,你可以使用 isNotEmpty 并简化条件

@ConditionalOnExpression(
    "T(org.apache.commons.lang3.StringUtils).isNotEmpty('${database.url:}')"
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接