如何让自定义配置值可在@ConditionalOnExpression注解中正常读取
问题根因
@ConditionalOnExpression 属于Spring条件注解,执行时机远早于普通Bean的实例化阶段:它在Bean定义注册的阶段就会执行SpEL表达式判断是否要注册对应Bean,此时你的FunctionalityConfig实例还没有被初始化并注册到Spring容器中,因此表达式找不到functionalityConfig这个Bean对象,触发EL1008E报错。
而你在Application类中使用的@Value是Bean实例化完成后的属性注入阶段才执行的,此时FunctionalityConfig已经完成初始化,所以可以正常读取到值。
解决方案
方案1:直接读取配置属性(推荐)
@ConditionalOnExpression可以直接读取环境中的配置参数,不需要依赖FunctionalityConfig Bean,修改注解中的SpEL表达式即可:
@ConditionalOnExpression("${com.example.config.functionality.rest-interface:false}")
注意Spring配置默认采用kebab-case命名规则,驼峰的restInterface对应配置中的rest-interface,末尾的:false表示找不到对应配置时默认值为false。
方案2:自定义Condition实现
如果需要更灵活的判断逻辑,可以放弃@ConditionalOnExpression,自己实现Condition接口:
首先定义条件类:
public class OnRestInterfaceCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { return context.getEnvironment() .getProperty("com.example.config.functionality.rest-interface", Boolean.class, false); } }
然后修改自定义注解:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional(OnRestInterfaceCondition.class) public @interface ConditionalOnRestInterface { }
这个方案执行效率和稳定性都更高,也不需要依赖FunctionalityConfig的初始化时机。
额外优化点
你的FunctionalityConfig上不需要同时加@Configuration和@ConfigurationProperties,如果已经在启动类加了@EnableConfigurationProperties(FunctionalityConfig.class),去掉@Configuration注解即可,避免重复注册Bean。
内容的提问来源于stack exchange,提问作者user2076898

