序
我个人的业务代码经常大量的使用@Autowired,一直没觉得有什么不妥,最近阅读到的一些东西,让我有了新的观点...
文
最近阅读了Halo,也就是本博客的源码,Halo中有很多注入的地方没有使用@Autowired。
而是用了有参构造器。
Halo的代码我觉得写的还是很漂亮的... 有点好奇Halo为什么这么写,于是仔细看了一直被我无视的Idea的 @Autowired 的建议。
也查阅了一些文章
结论:
如果字段很少,通常应该使用构造函数注入(从 Spring 4 开始就支持构造函数注入)。
为什么呢?
- @Autowired 我们工作中一般都是注入单例对象, @Autowired 设置值的时机是 在构造函数执行后,利用反射注入的,也就是说: 我们无法设置@Autowired注入的对象为 final, 注入的单例就存在被修改的可能。
-
注入单例对象,一般为必须的参数,但是 @Autowired并不能直观的显示出来,也没有任何提示,甚至可能出现必须的注入单例对象为null的现象. (这点我甚至生产环境中遇到过)。
-
如2所示,有参构造,编写测试类时候会更加容易,而且@Autowired没有反射或 Spring 容器就无法进行单元测试了。 (中枪了! 减少了测试依赖,轻易进行部分的单元测试,感觉这点很友好)。
这些让我想起了一次严重的生产事故!
起因是一个抽象父类的有个 @Autowired 注入的参数值,这个值负责控制 一些线程的超时无响应时候的自动唤醒时间,子类都为@Component的单例对象, 这些看上去一切都正常。
但是有位人员错误的使用了子类,自行的 New 的方式创建了子类对象进行操作,父抽象类中的值并未注入成功,但是却没有任何的提示。
开发人员也没有意识到错误,因为这些线程只会在网络不畅时候发生死锁(失去了超时自动唤醒),上线后部分服务网络不畅时,导致了经常的线程池耗尽, 引发的事故。
我当时用了将近一个星期来排查这个问题,一点一点的Debug, 模拟线上环境 才找到了死锁的位置。
当时只觉得他没有按照规范去开发,完全没有意识到自己的问题。
现在想起来,有参构造而非 @Autowired, 在构建对象时就有显式的提示必要的值,就可以避免这个问题,谁都有犯错的时候,人多了难免有低级错误, 完全依赖默认的规矩也是不可靠的..
参考文章:
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.auto-configuration
https://kknews.cc/zh-sg/news/ez8j3g4.html
https://stackoverflow.com/questions/62845494/autowired-says-field-injection-not-recommended
本文由 考拉 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Sep 16,2021