原文来自于:zha-ge.cn/java/106
不加 @Primary?Spring 自动装配时可能直接报错!
说来惭愧,前两天在写一个 Spring Boot 的小模块,自以为稳如老狗,结果居然在自动装配的时候遇到了个小坑,令人头大。事情经过非常"程序员":本来想着加几个接口实现,被 Spring 自动注入一把梭,谁能想到因为懒得加 @Primary
,瞬间红线飘满。
先说下现场背景
我们有个 Handler
接口,用于做一些数据处理。然后,有两个实现,FirstHandler
和 SecondHandler
,都是很普通的 Bean,分别处理不同的逻辑。平时加上 @Service
都习惯成自然了,哪想多了。
某天同事优化代码,顺手把 @Primary
给删了,想说"反正业务单一,应该没啥影响吧"。接着重启服务,结果后台直接报错------Spring 提示我:"哥们,你这注入有歧义啊,我可不知道要选哪一个!"
卡在自动注入的尴尬瞬间
你问会报什么错?经典的:
No qualifying bean of type 'com.xxxx.Handler' available: expected single matching bean but found 2: firstHandler,secondHandler
翻译一下就是:"你给我两把钥匙,我懒得猜你要哪把。" 此时,刚挣扎在 deadline 前的我整个人都停止了思考。
怎么破局呢?别慌,看代码!
最直观的做法,就是给其中一个实现加上 @Primary
:
java
@Service
@Primary
public class FirstHandler implements Handler {
// ...
}
妙啊!老哥一下子就乖了,容器世界风平浪静。
当然,也可以显式指定注入的 Bean 名:
java
@Autowired
@Qualifier("secondHandler")
private Handler handler;
效果一样,告诉 Spring:"我只要这一个,别找茬。"
你甚至可以自己 new ArrayList<>(applicationContext.getBeansOfType(Handler.class).values())
,手动管控。 不过,要我说,这种骚操作还是别轻易用,能偷懒就用 @Primary
,毕竟咱也是要维护幸福指数的。
踩坑瞬间
- 两个(或以上)同类型 Bean,只用
@Autowired
自动注入,必挂! - 忽视了团队中其他人可能扩展了实现类,交给 Spring 自己"猜",他根本懒得猜!
- 万一到处都是
Handler
,手动管理 BeanName,代码风格突然土了好多。
经验启示
- 自动装配不是万能的,有歧义一定要帮 Spring 做"选择题"。
- 业务明确的核心实现,优先加
@Primary
。 - 万一出现新需求,搞多实现,不要手抖删掉别人辛苦加的注解!
- 注入真的特别多实现类?手动指定
@Qualifier
,会让代码更清晰。
尾巴来一根
写代码就像在游戏里开盲盒,有时候运气不好,踩个小坑也算生活调味。 不加 @Primary
,分分钟让你怀疑人生,但加上以后,你会发现世界都安静了。
下回要加实现类的时候,记得问问自己------ "哥们,这次要不要给自己投个票啊?"
------完,休息一会,喝个可乐先。