当前位置: 首页 > 知识库问答 >
问题:

在@Configuration bean中的SpEL表达式中引用ConfigurationProperties bean

周浩博
2023-03-14

我有一个属性类:

import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("some")
    public class SomeProperties {
        private List<String> stuff;

        public List<String> getStuff() {
            return stuff;
        }

        public void setStuff(List<String> stuff) {
            this.stuff = stuff;
        }    
    }

我在@Configuration类中启用配置属性,如下所示:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(SomeProperties.class)
public class SomeAutoConfiguration {    
}

在同一个类(“SomeAutoConfiguration”)中,我想创建另一个bean,具体取决于SomeProperties中的list属性是否为空。我想我可以将@ConditionalExpression与以下SpEl结合使用:

@Bean
@ConditionalOnExpression("!(#someProperties.stuff?.isEmpty()?:true)")   
    public Object someBean(final SomeProperties someProperties) {
    return new Object();
}    

SpEl是正确的,但我无法获得包含我的属性的bean。使用上面的表达式,我遇到了

EL1007E:(位置43):在null上找不到属性或字段“stuff”

试着让豆子的名字像

@Bean
@ConditionalOnExpression("!(@'some.CONFIGURATION_PROPERTIES'.stuff?.isEmpty()?:true)")  
    public Object someBean(final SomeProperties someProperties) {
    return new Object();
} 

结束在

NoSuchBeanDefinitionException:没有名为“some”的bean。定义了“配置属性”

有什么想法吗?我已经尝试在另一个类中启用ConfigurationProperties,但这也不起作用。

共有3个答案

梁研
2023-03-14

根据Brice的回答,我提出了一个抽象条件:

public abstract class ConfigurationPropertyCondition<T> extends SpringBootCondition {
    private final Class<T> propertiesClass;
    private final Supplier<T> constructor;
    private final String prefix;
    private final Predicate<T> predicate;

    public ConfigurationPropertyCondition(
            Class<T> propertiesClass, Supplier<T> constructor, String prefix, Predicate<T> predicate) {
        this.propertiesClass = propertiesClass;
        this.constructor = constructor;
        this.prefix = prefix;
        this.predicate = predicate;
    }

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return new ConditionOutcome(predicate.test(properties(context)), (String) null);
    }

    private T properties(ConditionContext context) {
        return Binder.get(context.getEnvironment())
                .bind(ConfigurationPropertyName.of(prefix), Bindable.of(propertiesClass))
                .orElseGet(constructor);
    }
}

现在我可以做一些类似的事情:

...
@ConfigurationProperties(prefix = MY_FEATURE_SETTINGS)
@Bean
public MyFeatureProperties myFeatureProperties() {
    return new MyFeatureProperties();
}
...

@Conditional(MyFeatureConfiguration.MyFeatureEnabled.class)
@Configuration
public class MyFeatureConfiguration {
    ...

    static class MyFeatureEnabled extends ConfigurationPropertyCondition<MyFeatureProperties> {
        public MyFeatureEnabled() {
            super(MyFeatureProperties.class, MyFeatureProperties::new, MY_FEATURE_SETTINGS, MyFeatureProperties::isEnabled);
        }
    }
}

谷博艺
2023-03-14

为了补充@PhilWebb关于Spring Boot 2的回答,已删除了RelaxedProperty tyResolver,以支持更健壮的名为Binder的替代方案。这里有一个非常简单的例子:

@Configuration
@AutoConfigureBefore(JacksonAutoConfiguration.class)
@ConditionalOnMissingBean(ObjectMapper.class)
@Conditional(SpringJacksonPropertiesMissing.class)
public class ObjectMapperConfiguration {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .disable(FAIL_ON_UNKNOWN_PROPERTIES)
                .setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    static class SpringJacksonPropertiesMissing extends SpringBootCondition {
        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context,
                                                AnnotatedTypeMetadata metadata) {
            return new ConditionOutcome(hasJacksonPropertiesDefined(context),
                                        "Spring Jackson property based configuration missing");
        }

        private boolean hasJackonPropertiesDefined(ConditionContext context) {
            return Binder.get(context.getEnvironment())
                         .bind(ConfigurationPropertyName.of("spring.jackson"),
                                                Bindable.of(Map.class))
                         .orElse(Collections.emptyMap())
                         .isEmpty();
        }
    }
}

免责声明:此代码用于逐步淘汰一些关于jackson对象映射器的错误做法,以便将一些代码转换为Spring Boot方式来配置对象映射器。

高弘光
2023-03-14

我认为您所面临的问题是,在解析@Configuration类时会计算@Conditions,因此不能保证SomePropertiesbean已经定义。即使定义了它,您也可能不希望它被提前初始化,所以我建议使用不同的方法。

您可以尝试@msgtionalOnPropty,这是Spring Boot在有条件地希望基于属性启用自动配置时在内部使用的注释。如果不够灵活,您可以创建自己的条件并直接访问环境来判断属性值是否为空。如果您想支持灵活的绑定,您可以使用RelaxedProperty tyResolver。这里有一个例子。

 类似资料:
  • 问题内容: 我正在尝试使用SpEL根据我定义的一些规则将同一文档加载到不同的集合中。 因此,从我所拥有的开始: -首先文件: -秒我有应该提供集合名称的提供者bean: 问题是,当我尝试将文档插入应由提供程序生成的特定集合中时,我得到以下stacktrace: org.springframework.expression.spel.SpelEvaluationException:EL1057E :

  • 主要内容:示例,SpEL对Bean定义的支持,SpEL中的运算符,SpEL中的变量Spring Expression Language(简称 SpEL)是一种功能强大的表达式语言,支持运行时查询和操作对象图 。表达式语言一般是用最简单的形式完成最主要的工作,以此减少工作量。 Java 有许多可用的表达式语言,例如 JSP EL,OGNL,MVEL 和 JBoss EL,SpEL 语法类似于 JSP EL,功能类似于 Struts2 中的 OGNL,能在运行时构建复杂表达式、存取

  • 长话短说: 是否有一种方法可以将生成的字符串解释为注释中的SpEL表达式,而不使用转换器,例如)? 我认为将被宏展开,然后由计算为对应的SpEL表达式,上面示例中的。不幸的是,情况并非如此,加载Spring上下文会导致一个错误,说明它无法将字符串(属性的值)转换为目标类型。 现在,我通过编写一个实现的类来解决这个问题,但这非常复杂,因为我需要通过实例化等以编程方式将字符串计算为SpEL表达式。 但

  • 问题内容: 如何在MySQL中使用正则表达式引用组?我试过了: 但它不起作用。这个怎么做? 问题答案: 您不能,在MySql中无法引用正则表达式捕获组。

  • 我有一个带表单的thymeleaf代码片段。我想验证这张表格。 这里有个例外: ${#fields.haserrors('name')} 那么我如何将name param放入引号中呢?

  • 问题内容: 有没有办法让AngularJS在模型数据中评估表达式? HTML: 模型: 最终结果将是:。 问题答案: 您可以使用该服务来插值字符串… JSFiddle