Spring高手之路-Spring支持的注入方式、Spring为什么不建议使用基于字段的依赖注入

目录

Spring支持的注入方式

1.字段注入

2.构造器注入

3.setter注入

使用构造器注入存在的问题

Spring为何不建议使用基于字段的依赖注入

1.单一职责问题

2.可能产生NPE(空指针异常)

3.隐藏依赖

4.不利于测试


Spring支持的注入方式

1.字段注入

 @Autowired
 private UserDao userDao;

2.构造器注入

@Component
public class UserService {

    private UserDao userDao;

    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;

    }

}

3.setter注入

@Component
public class UserService {

    private UserDao userDao;


    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

}

使用构造器注入存在的问题

如果我们的两个Bean循环依赖,就会抛出该异常

Error creating bean with name 'beanOne': Requested bean is currently in creation: ls there an
unresolvable circular reference?

@Component
public class UserService {
    private OrderService orderService;


    @Autowired
    public UserService(OrderService orderService){
        this.orderService=orderService;
    }
}

@Component
public class OrderService {

    private UserService userService;


    @Autowired
    public OrderService(UserService userService){
        this.userService=userService;
    }

}

如果出现两个类循环引用彼此,说明代码的设计存在问题,如果临时无法解决可以使用以下两种解决方法:

1.使用@Lazy注解设置为懒加载,令其中一个类延迟初始化,使得它在首次使用时才进行初始化,OrderService在初始化时可以不需要UserService的实例,避免了循环依赖的问题

@Component
@Lazy
public class UserService {
    private OrderService orderService;

    @Autowired
    public UserService(@Lazy OrderService orderService) {
        this.orderService = orderService;
    }
}

@Component
public class OrderService {
    private UserService userService;

    @Autowired
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}

2.使用setter注入,将构造器注入修改为setter注入,这样可以确保构造函数的参数已经被完全初始化,避免了循环依赖的问题。

@Component
public class UserService {
    private OrderService orderService;

    public UserService() {}

    @Autowired
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}
@Component
public class OrderService {
    private UserService userService;

    public OrderService() {}

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

Spring为何不建议使用基于字段的依赖注入

当你使用字段注入IDEA会给你如下警告

spring官网文档也指出强制依赖使用构造函数注入,可选依赖使用setter注入

官网文档地址:

依赖注入 :: Spring Frameworkicon-default.png?t=N7T8https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html

使用字段注入会带来如下问题:

1.单一职责问题


我们都知道,根据SOLID设计原则来进,一个类的设计应该符合单一职责原则,就是一个类只能做一件功能,当我们使用基于字段注入的时候,随着业务的暴增,字段越来越多,我们是很难发现我们已经默默中违背了单一职责原则的。

但是如果我们使用基于构造器注入的方式,因为构造器注入的写法比较臃肿,所以它就在间接提醒我们违背了单一职责原则,该做重构了

//基于字段注入
@Component
public class OrderService {

    @Autowired
    private UserService userService;
    @Autowired
    private GoodsService goodsService;

}
//基于构造器的注入
@Component
public class OrderService {
    
    private UserService userService;
    private GoodsService goodsService;
    
    @Autowired
    public OrderService(UserService userService ,GoodsService goodsService){
        this.userService=userService;
        this.goodsService=goodsService;
    }
}

2.可能产生NPE(空指针异常

对于一个bean来说,它的初始化顺序为:静态变量或静态语句块 ->实例变量或初始化语句块 -> 构造方法 -> @Autowired。

所以,在静态语句块,初始化语句块,构造方法中使用Autowired表明的字段,都会引起NPE问题

@Component
public class OrderService {
    @Autowired
    private UserService userService;
  
    private String orderId;



    public OrderService(){
        //此时的OrderService还未初始化,会抛出空指针异常
        this.orderId= userService.getUserId();
    }
}

相反的,用构造器的依赖注入,就会实例化对象,在使用的过程中字段一定不为空

3.隐藏依赖

对于一个正常的使用依赖注入的Bean来说,它应该“显式”的通知容器,自己需要哪些Bean,可以通过构造器通知,public的setter方法通知,这些设计都是没问题的。


外部容器不应该感知到Bean内部私有字段(如上例中的private UserService)的存在,私有字段对外部应该是不可见的。由于私有字段不可见,所以在设计层面,我们不应该通过字段注入的方式将依赖注入到私有字段中。这样会破坏封装性。


所以,当我们对字段做注入的时候,Spring就需要关心一个本来被我们封装到一个bean中的私有成员变量,这就和他的封装性违背了。因为我们应该通过setter或者构造函数来修改一个字段的值。

4.不利于测试

很明显,使用了Autowired注解,说明这个类依赖了Spring容器,这让我们在进行UT的时候必须要启动个Spring容器才可以测试这个类,显然太麻烦,这种测试方式非常重,对于大型项目来说,往往启动一个容器就要好几分钟,这样非常耽误时间。


不过,如果使用构造器的依赖注入就不会有这种问题,或者,我们可以使用Resource注解(@Resource是Java EE提供的注解,更加通用且符合J2EE标准,可以在不同的Java EE容器中使用)也可以解决上述问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/273652.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s的二进制部署: 源码包部署-----node节点部署

服务器IP软件包k8s--master0120.0.0.61kube-aplserver,kube-controer-manager,kube-scheduler,etcdk8s--master0220.0.0.62kube-controer-manager,kube-schedulernode节点0120.0.0.62kubelet,kube-proxy,et…

【http】HTTP/1.0、HTTP/1.1和HTTP/2.0

✨ 专栏介绍 在当今互联网时代,计算机网络已经成为了人们生活和工作中不可或缺的一部分。而要实现计算机之间的通信和数据传输,就需要依靠各种网络协议来进行规范和约束。无论是浏览网页、发送电子邮件还是进行在线交流,都离不开各种各样的网…

2023年航天大事件

2023年,中国完成宇航发射近70次,是中国航天新的里程碑。中国科技工作者继续推进航天科技创新,并在运载火箭发动机研制固体燃料火箭研发、可重复航天器研发等方面取得重大突破;继续推进载人航天工程、北斗工程等中国重大航天旗舰工…

HOJ 项目部署-前端定制 默认勾选显示标签、 在线编辑器主题和字号大小修改、增加一言功能 题目AC后礼花绽放

# 项目拉取地址: https://gitee.com/himitzh0730/hoj.git # 切换到hoj-vue目录执行以下命令 #安装依赖 npm install #运行服务 npm run serve #修改代码后构建项目到dist文件夹,到服务器docker-compose.yml中修改hoj-frontend文件映射即可 npm run build…

python进阶 — Python解释器

1、Python解释器 Python解释器是一个计算机程序,它将Python代码转换为计算机可以理解的机器代码,并执行这些机器代码。 1. 这篇文章介绍如何下载和安装Python解释器: python基础(2)— 环境搭建 2 . 这篇文章介绍如…

果然,大厂都在卷这个!

大家好,我是鱼皮。首先祝大家平安夜快乐!给大家看看我们搞的小圣诞树哈哈~ 言归正传,这周中我去北京待了 2 天,主要是收到百度的邀请去参加百度云的智算大会,听说有些 AI 产品要发布。 我自己是非常关注国内…

C#教程(四):多态

1、介绍 1.1 什么是多态 在C#中,多态性(Polymorphism)是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息做出响应,即同一个方法可以在不同的对象上产生不同的行为。C#中的多态性可以通过以下几种方式实现…

每日一题-----逆序字符串

大家好我是Beilef,在一个美好的下午我意外接触到编程并且产生了兴趣,哈哈我要努力成为一个跨界者,让我们一起加油吧O(∩_∩)O 文章目录 目录 文章目录 前言 大家好请上车 一、逆序字符串 题⽬描述: 输⼊⼀个字符串,写…

UiPath报告 | 2024年7大自动化和Al趋势

在自动化与人工智能的合力推动下,全球企业正在步入一个创造价值的新纪元。 预计市场将涌现出一系列高潜力的AI应用实例; 企业的日常运营和复杂流程管理方式将面临根本性的变革,人工智能的崛起正加速企业自动化进程,促成价值的快速…

【WPF】使用Behavior以及ValidationRule实现表单校验

文章目录 使用ValidationRule实现检测用户输入EmptyValidationRule 非空校验TextBox设置非空校验TextBox设置非空校验并显示校验提示 结语 使用ValidationRule实现检测用户输入 EmptyValidationRule是TextBox内容是否为空校验,TextBox的Binding属性设置ValidationRu…

Centos7:Jenkins+gitlab+node项目启动(1)

安装Jenkins 虚拟机配置 需要的软件 https://download.csdn.net/download/myy2012/88668255 解压到目录 用xftp 上传 开始安装jdk rmp -ivh jdk-8u181-linux-x64.rpm 开始安装jenkins rmp -ivh jenkins-2.99-1.1.noarch.rpm 修改用户与端口(端口按需修改) vim /etc/sy…

Matlab之State Flow

打开方式 方式一:在命令窗口输入State Flow或者简写sf就能打开,并且会自动打开State Flow 的Library。从左到右分别是图表、真值表、状态转换表、例子、顺序查看,可以加入到Simulink当中。 方式二:从Simulink Library里面添加Sta…

Xshell 从github克隆项目:使用ssh方式。

接上文: https://blog.csdn.net/liu834189447/article/details/135247868 是能克隆项目了,但是速度太磕碜了,磕碜到难以直视。 找到另外一种办法,使用SSH克隆项目 速度嘎嘎猛。 首先得能进得去github网站,不能点上边…

Pikachu靶场 “Http Header”SQL注入

1. 先在 pikachu 打开 Http Header 注入模块,点击提示 查看登录 账号 和 密码,登陆后去 Burp 中找到登陆的 GET请求 2. 设置payload1 :在 User-Agent最后 输入 查看 数据库名 or updatexml(1,concat(0x7e,database()),0) or 查看 用户名…

File Inclusion(Pikachu)

File Inclusion(local) 这里随便点击一个提交 观察url,显示是一个文件file1.php 可以直接通过url修改这个文件 找到自己的文件(本地文件)shell.php的路径写上去 就可以看到 File Inclusion(remote) 提交的是一个目标…

uni-app和Vue.js有什么区别?

Hello,大家好,我是咕噜铁蛋!在当今的前端开发领域,uni-app和Vue.js都是非常热门的技术。很多开发者经常在选择时感到困惑。今天铁蛋这篇文章讲和大家探讨这两者的区别,帮助各位在开发路上做出明智的选择。 1. uni-app是…

Java日期工具类时间校验

Java日期工具类时间校验 嘚吧嘚正则表达式版本一版本二版本三 SimpleDateFormat工具类 嘚吧嘚 时间校验这个问题,我在网上找了很多资料,有用正则表达式的、有用格式工具类的。🤨 其实都能实现时间校验,既然两种方式都能实现&…

【Java基础系列】equals方法使用与总结

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Python模拟动态星空

前言 今天,我们来用Python做个星空。 一、模拟星空 1,.首先导入所需要的库: from turtle import * from random import random, randint 2.初始画面: screen Screen() width, height 800, 600 screen.setup(width, height) screen.tit…

Kubernetes (四) 资源清单及yaml文件详解

一. 资源清单 二. 编写yaml文件及内容详解 常用命令 …