使用@Conditional注解导致嵌套Bean触发BeanCreationException问题咨询
我在Spring 4.x中使用@Conditional注解控制Bean注册,代码如下:
@Controller class SchoolController{ @Autowired @Qualifier("studentProcessor") private StudentProcessor studentProcessor; //Some code } @Component("studentProcessor") class StudentProcessor{ @Autowired private SportService sportService; //Some code } @Component @Conditional(ServiceCondition.class) class SportService{ //Some code } class ServiceCondition implements Condition{ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { //Some condition } }
启动Tomcat时抛出异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'studentProcessor': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.student.service.SportService com.student.processors.StudentProcessor.sportService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.student.service.SportService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
现在有两个问题:
- 这属于预期行为吗?
- 若不属于,该如何解决此问题?
问题解答
1. 这确实是预期行为
道理很直白:你的StudentProcessor通过默认的@Autowired(required=true)强制要求注入SportService,但当ServiceCondition的matches方法返回false时,Spring不会将SportService注册到容器中。此时容器里找不到符合要求的SportService实例,自然会抛出依赖缺失的异常——毕竟你明确要求必须注入这个Bean,但它压根不存在。
简单说,@Conditional的核心作用就是决定Bean是否能进入容器,当条件不满足时Bean消失,而依赖它的Bean又坚持要这个依赖,冲突必然发生,这完全是Spring按照规则执行的正常结果。
2. 解决方法按业务场景选
根据你的实际需求,有几种常用的处理方案:
降低依赖的强制性:把
StudentProcessor里的@Autowired改成非必填模式,也就是设置required=false:@Autowired(required = false) private SportService sportService;这样就算
SportService不存在,Spring也能正常创建StudentProcessor,你只需要在代码里判断sportService是否为null,再做对应的逻辑分支处理。绑定两个Bean的条件:给
StudentProcessor也加上同样的@Conditional注解,让它的注册和SportService绑定在一起——当SportService不满足条件时,StudentProcessor也不注册:@Component("studentProcessor") @Conditional(ServiceCondition.class) class StudentProcessor{ @Autowired private SportService sportService; //Some code }这样两个Bean要么同时存在,要么同时不存在,就不会出现依赖找不到的问题。
提供默认实现:如果
SportService条件不满足时需要一个兜底的Bean,可以创建一个默认的SportService实现类,自己实现一个类似"当SportService不存在时生效"的Condition(Spring 4.x本身没有@ConditionalOnMissingBean,如果升级到Spring Boot可以直接用这个注解),或者用@Primary配合条件注解,确保默认Bean在条件不满足时顶上去。修正Condition逻辑:检查你的
ServiceCondition的matches方法,看看是不是逻辑判断有误导致SportService没被正确注册——比如读取配置时出错、环境判断不符合预期,修正后让SportService在需要的时候能正常进入容器。
内容的提问来源于stack exchange,提问作者Abhijit

