Spring为啥不推荐使用@Autowired注解?
引言
使用IDEA开发时,同组小伙伴都喜欢用@Autowired注入,代码一片warning,看着很不舒服,@Autowired作为Spring的亲儿子,为啥在IDEA中提示了一个警告:Field injection is not recommended
想搞清楚这个问题之前,首先先了解一下依赖注入的几种方式
Spring的三种注入方式
属性(filed)注入
这种注入方式就是在bean的变量上使用注解进行依赖注入。本质上是通过反射的方式直接注入到field。这是我平常开发中看的最多也是最熟悉的一种方式。
@Autowired UserDao userDao; 复制代码
构造器注入
将各个必需的依赖全部放在带有注解构造方法的参数中,并在构造方法中完成对应变量的初始化,这种方式,就是基于构造方法的注入。比如:
final UserDao userDao; @Autowired public UserServiceImpl(UserDao userDao) { this.userDao = userDao; } 复制代码
set方法注入
通过对应变量的setXXX()方法以及在方法上面使用注解,来完成依赖注入。比如:
private UserDao userDao; @Autowired public void setUserDao (UserDao userDao) { this.userDao = userDao; } 复制代码
属性注入可能出现的问题
问题一
基于 field 的注入可能会带来一些隐含的问题。来我们举个例子:
@Autowired private User user; private String company; public UserDaoImpl(){ this.company = user.getCompany(); } 复制代码
编译过程不会报错,但是运行之后报NullPointerException
Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [...]: Constructor threw exception; nested exception is java.lang.NullPointerException 复制代码
Java 在初始化一个类时,是按照静态变量或静态语句块 –> 实例变量或初始化语句块 –> 构造方法 -> @Autowired 的顺序。所以在执行这个类的构造方法时,user对象尚未被注入,它的值还是 null。
问题二
不能有效的指明依赖。相信很多人都遇见过一个bug,依赖注入的对象为null,在启动依赖容器时遇到这个问题都是配置的依赖注入少了一个注解什么的。这种方式就过于依赖注入容器了,当没有启动整个依赖容器时,这个类就不能运转,在反射时无法提供这个类需要的依赖。
问题三
依赖注入的核心思想之一就是被容器管理的类不应该依赖被容器管理的依赖,换成白话来说就是如果这个类使用了依赖注入的类,那么这个类摆脱了这几个依赖必须也能正常运行。然而使用变量注入的方式是不能保证这点的。
spring建议
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.
翻译过来就是:
强制依赖就用构造器方式
可选、可变的依赖就用setter注入
使用@Resource代替@Autowired
@Resource有2个属性name和type。在spring中name属性定义为bean的名字,type这是bean的类型。如果属性上加@Resource注解那么他的注入流程是
- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
- 如果指定了name,则从上下文中查找名称匹配的bean进行装配,找不到则抛出异常。
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
- 如果既没有指定name,又没有指定type,则默认按照byName方式进行装配;如果没有匹配,按照byType进行装配。
@Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。
使用@RequiredArgsConstructor构造器方式注入
这种形式就是Spring推荐使用的构造器方式注入,此种方式是lombok包下的注解,如果使用此种方式,需要项目中引入lombok,例如:
@RequiredArgsConstructor public class UserDaoImpl{ private final User user; } 复制代码
最后
如果你觉得此文对你有一丁点帮助,点个赞。或者可以加入我的开发交流群:1025263163相互学习,我们会有专业的技术答疑解惑
如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu不胜感激 !

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
程序员的开源月刊《HelloGitHub》第 67 期
兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 分享 GitHub 上有趣、入门级的开源项目。 https://github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等,涵盖多种编程语言 Python、Java、Go、C/C++、Swift...让你在短时间内感受到开源的魅力,对编程产生兴趣! 以下为本期内容|每个月 28 号更新 C 项目 1、bytehound:更强大的 Linux 内存分析工具。它能够显示内存变化曲线、占用详情、完整的堆栈记录等信息,有助于解决内容泄漏等问题 2、nnn:几乎不需要配置就能用的终端文件管理工具。它运行仅需极少的内存但功能却不少,支持文件实时预览、搜索、批量操作文件、排序等,不仅如此它还能作为插件整合进 Vim C# 项目 3、ShareX:免费的 Windows 截屏录制工具。功能强大支持全屏截图、滚动截图、检测窗口截图、GIF 录制等,截图后还支持在图片上增加文字、水印、特效、马赛克等,最后可直接上传图床得到链接,丝滑地完成整个截图流程 C++ 项目 4...
- 下一篇
NoOps 来了,是否意味着 DevOps 时代的终结?
随着云技术采用率不断上升,应用程序架构的抽象级别也有所提高——从传统的本地服务器迁移到了容器和无服务器部署。自动化技术也已经发展到了让人工流程不再是首选的地步,即使是备份、安全管理和补丁更新等与基础设施相关的活动也更多通过自动化来执行。这种理想状态相当于一种 NoOps 环境,在这样的环境中负责管理你的应用程序生命周期的团队可以变得很小。理想情况下,在这样的环境中,你的运营团队所做的那些工作都没必要做了。 毫无疑问,DevOps 现在已经深深融入所有云优先组织的 DNA 中,如今成为了一种常态,而不是什么稀罕事物。云应用程序需要敏捷性,而 DevOps 提供了这种敏捷性。然而,NoOps 是否意味着 DevOps 时代的终结?还是说它只是 DevOps 的下一个发展阶段呢? DevOps vs. NoOps DevOps 的成功与否在很大程度上取决于你的开发和运营团队之间的协作水平,因为它将系统管理员和开发人员聚集在一起,打破了他们各自业务之间的障壁。与此同时,持续集成和持续部署的流程在 DevOps 中至关重要,它们有助于及早发现并预防问题,这反过来又会加快解决方案的交付速度。但请注...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果