为何@Qualifier注解无法作用于final成员变量?
问题
在SpringBoot开发中,发现@Qualifier注解无法作用于final成员变量,具体场景:
- 若Person类的Vehicle成员变量声明为final,会抛出
NoUniqueBeanDefinitionException异常; - 若不声明为final,则不会抛出异常,但vehicle变量为null。
代码示例
配置类(定义Vehicle Bean)
// 2个Vehicle Bean使用@Qualifier注解标记; @Configuration public class Config { @Bean @Qualifier("vehicle1") Vehicle vehicle1() { var veh = new Vehicle(); veh.setName("Benz"); return veh; } @Bean @Qualifier("vehicle2") Vehicle vehicle2() { var veh = new Vehicle(); veh.setName("BMW"); return veh; } }
Person类(含final成员变量)
// Person类拥有final类型的Vehicle成员变量 @Component @Data public class Person { private String name="Mike"; @Qualifier("vehicle2") private final Vehicle vehicle; }
抛出的异常
No qualifying bean of type 'project1.Vehicle' available: expected single matching bean but found 2: vehicle1,vehicle2
原因分析与解决方案
1. final成员变量抛出异常的原因
Java中final字段初始化后不可修改,Spring的字段注入依赖反射修改字段值,无法直接给final字段赋值。此时Spring会 fallback 到构造器注入逻辑,但你的Person类没有显式定义接收Vehicle参数的构造器(@Data不会自动生成带final字段的构造器),Spring只能调用无参构造器创建实例。
但此时容器里有两个Vehicle类型的Bean,Spring不知道该选哪一个注入,因此抛出NoUniqueBeanDefinitionException。
2. 非final成员变量为null的原因
你只给字段加了@Qualifier,没加@Autowired——Spring的字段注入需要@Autowired触发注入逻辑,缺少它的话Spring不会尝试给该字段赋值,所以vehicle保持null,自然也不会因为Bean冲突抛出异常。
正确实现方式
方式一:构造器注入(官方推荐,支持final字段)
@Component @Data public class Person { private String name="Mike"; private final Vehicle vehicle; // 显式构造器,通过@Qualifier指定要注入的Bean public Person(@Qualifier("vehicle2") Vehicle vehicle) { this.vehicle = vehicle; } }
方式二:字段注入(需配合@Autowired)
@Component @Data public class Person { private String name="Mike"; @Autowired @Qualifier("vehicle2") private Vehicle vehicle; // 若要保留final,建议用构造器注入 }
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

