如何创建需依赖注入的Spring自定义Condition?
问题分析
Spring的@Conditional注解在Bean注册阶段执行逻辑,此时IoC容器还未完成普通Bean的实例化和依赖注入。当你给@Conditional传入FavoriteColorsAreCoolCondition.class时,Spring会直接通过反射实例化这个Condition类,而非从容器中获取你注册的Condition Bean——这就是为什么你即使注册了Condition Bean,依然会收到"缺少默认构造函数"的报错。
同时,你的IFavoriteColorFinder依赖在Bean注册阶段还未被实例化,无法通过构造函数注入到Condition中,这是Spring生命周期的固有限制。
可行解决方案
方案一:通过ConditionContext获取BeanFactory延迟获取依赖
利用ConditionContext提供的BeanFactory,通过BeanProvider延迟获取依赖Bean,既避免了过早初始化的问题,也不需要给Condition添加无参构造。
修改后的Condition代码:
import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.beans.factory.BeanProvider; public final class FavoriteColorsAreCoolCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 获取BeanProvider,支持安全、延迟获取Bean实例 BeanProvider<IFavoriteColorFinder> colorFinderProvider = context.getBeanFactory().getBeanProvider(IFavoriteColorFinder.class); // 检查依赖Bean是否存在,再执行判断逻辑 IFavoriteColorFinder colorFinder = colorFinderProvider.getIfAvailable(); if (colorFinder != null) { String favoriteColor = colorFinder.findFavoriteColor(); return "red".equalsIgnoreCase(favoriteColor); } // 依赖不存在时的默认返回值,可根据需求调整 return false; } }
配置类只需保留依赖Bean和带@Conditional的Bean:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; @Configuration public class CompositionRootJavaConfig { @Bean public IFavoriteColorFinder getAnIFavoriteColorFinder() { return new FirstConcreteIFavoriteColorFinder(); } @Conditional(FavoriteColorsAreCoolCondition.class) @Bean public ArithmeticException addArithmeticException() { return new ArithmeticException("This exists to test if FavoriteColorsAreCoolCondition works or not"); } }
方案二:使用ConfigurationCondition控制执行时机
如果你的依赖Bean在其他配置类中,需要确保依赖先被注册,可以实现ConfigurationCondition接口,指定Condition的执行时机为REGISTER_BEAN阶段(即所有Bean定义注册完成后),进一步保证依赖Bean的定义已存在。
代码示例:
import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.ConfigurationCondition; import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.beans.factory.BeanProvider; public final class FavoriteColorsAreCoolCondition implements ConfigurationCondition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { BeanProvider<IFavoriteColorFinder> colorFinderProvider = context.getBeanFactory().getBeanProvider(IFavoriteColorFinder.class); IFavoriteColorFinder colorFinder = colorFinderProvider.getIfAvailable(); if (colorFinder != null) { String favoriteColor = colorFinder.findFavoriteColor(); return "red".equalsIgnoreCase(favoriteColor); } return false; } @Override public ConfigurationPhase getConfigurationPhase() { // 指定在Bean注册完成后执行Condition判断 return ConfigurationPhase.REGISTER_BEAN; } }
关键注意事项
- 不要尝试给Condition添加构造函数依赖,也无需注册Condition为Bean——
@Conditional只会直接实例化你传入的Class类型,不会使用容器中的Condition实例。 - 使用
BeanProvider而非直接调用getBean(),避免因依赖Bean未初始化导致的异常,getIfAvailable()会在Bean不存在时返回null,更安全。
内容的提问来源于stack exchange,提问作者granadaCoder
相关产品推荐
相关产品推荐

