项目实战--不推荐使用@Autowired实现注入

news2024/9/19 16:09:27

不推荐使用@Autowired实现字段注入

  • 一、前言
  • 二、字段注入
    • 2.1 字段注入的使用
    • 2.2 字段注入的弊端
      • 2.2.1 与Spring的IOC机制紧密耦合
      • 2.2.2 无法使用final修饰符
      • 2.2.3 隐藏依赖性
      • 2.2.4 无法对注入的属性进行安全检查
      • 2.2.5 掩饰单一职责的设计思想
  • 三、设值注入
  • 四、构造器注入
  • 五、总结

一、前言

在这里插入图片描述

Spring框架被广泛应用于Java程序程序开发,而最近对公司的code review校验,有个硬性规定是:不允许使用@Autowired进行字段注入(field injection),推荐改为构造器注入(constructor injection)或设值注入(setter injection)。因此记录原因,以便后续开发借鉴。

二、字段注入

2.1 字段注入的使用

字段注入是指直接在类的字段(成员变量)上使用@Autowired注解,以实现依赖的注入。如:

@Service
public class EmployeeServiceImpl implements EmployeeService{
	@Autowired
	private EmployeeMapper employeeMapper;
 	
 	// 业务实现......
}

使用@Autowired注解基于字段的依赖注入编码时,IDEA也会出现弱警告:

Always use constructor based dependency injectionin your beans.
Always use assertions for mandatorydependencies

始终在 bean 中使用基于构造函数的依赖注入。始终对强制依赖项使用断言

且官方从Spring 4.0开始不推荐使用@Autowired进行字段注入。

2.2 字段注入的弊端

2.2.1 与Spring的IOC机制紧密耦合

这种方式把控制权全给Spring的IOC,强依赖于依赖注入框架,其他类想重新设置下该类的某个注入属性,必须通过反射处理,得到的结果再次与Spring类注入器耦合,就失去通过自动装配类字段而实现的对类的解耦,从而使类在Spring容器之外无效.,即对于IOC容器以外的环境,除使用反射来提供它需要的依赖之外,无法复用该实现类。

2.2.2 无法使用final修饰符

由于字段注入是在对象实例化之后进行的,字段不能用final修饰。这会导致以下问题:

  • 不变性(immutability)问题:无法确保依赖关系在对象生命周期内保持不变,从而可能引发难以调试的bug。
  • 设计上的局限:无法利用Java语言的特性来设计出更稳固和安全的代码结构。

2.2.3 隐藏依赖性

使用Spring的IOC,要求被注入的类用public修饰方法(构造方法/setter类型方法)来向外界表达需要什么依赖。但字段注入将依赖关系隐藏在类的内部,基本都是private修饰的,把属性都封印到class当中。

2.2.4 无法对注入的属性进行安全检查

在程序启动的时无法获取这个类,只有在真正业务接口调用时才会获取,若注入的是null,因为Spring不会对依赖的bean是否为null进行判断,不调用接口将一直无法发现NullPointException的存在,想在属性注入的时候,增加验证措施,也无法办到。

2.2.5 掩饰单一职责的设计思想

若使用构造函数的依赖注入,代码会臃肿,如下:

@Service
public class VerifyServiceImpl implents VerifyService{
  private AccountService accountService;
  private UserService userService;
  private IDService idService;
  private RoleService roleService;
  private PermissionService permissionService;
  private EnterpriseService enterpriseService;
  private EmployeeService employService;
  private TaskService taskService;
  private RedisService redisService;
  private MQService mqService;
 
  public SystemLogDto(AccountService accountService, 
                      UserService userService, 
                      IDService idService, 
                      RoleService roleService, 
                      PermissionService permissionService, 
                      EnterpriseService enterpriseService, 
                      EmployeeService employService, 
                      TaskService taskService, 
                      RedisService redisService, 
                      MQService mqService) {
      this.accountService = accountService;
      this.userService = userService;
      this.idService = idService;
      this.roleService = roleService;
      this.permissionService = permissionService;
      this.enterpriseService = enterpriseService;
      this.employService = employService;
      this.taskService = taskService;
      this.redisService = redisService;
      this.mqService = mqService;
  }
}

自然而然的会思考这个类是否违反单一职责思想,而使用字段注入就不会察觉到,甚至会很沉浸在@Autowire当中。

ps:

而现实情况是绝大多数项目都是使用@Autowired实现字段注入,虽然使用方式是最简单,但是也是最不推荐的,若非要使用也是推荐使用 @Resource

三、设值注入

设值注入是通过类的setter方法来注入依赖关系。示例:

@Controller
@RequestMapping("/employee")
public class EmployeeController {
    
    private EmployeeMapper employeeMapper;
    
    @Autowired
    public void setEmployeeMapper(EmployeeMapper employeeMapper) {
        this.employeeMapper = employeeMapper;
    }
}

或者:

@Service
public class MyServiceImpl implents MyService {

    private EmployeeService employeeService;
    
    @Autowired
    public void setEmployeeService(EmployeeService employeeService) {
        this.employeeService= employeeService;
    }
    // class implementation
}

调用:

public class MyServiceImplTest {
    private EmployeeService empService = Mockito.mock(EmployeeService.class);
    private MyServiceImpl myService = new MyServiceImpl();
    @Before
    public void setUp() {
        myService.setEmployeeService(empService);
    }
    @Test
    public void testServiceMethod() {
        // test implementation
    }
}

优点:

  • 相比构造器注入,set注入类似于选择性注入。
  • 允许在类构造完成后重新注入。
    缺点:
    这种方法是 Spring3.X 版本比较推荐的,但是基本上没见到有人用过。

四、构造器注入

这就是目前 Spring 最推荐的注入方式,直接通过带参构造方法来注入。
例如:

// 部分代码
@Component
public class RedisIdWorker {

    private StringRedisTemplate stringRedisTemplate;

    public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }
}

或者:

public class UserServiceImpl implements UserService {
    private final BCryptPasswordEncoder passwordEncoder;
    private final UserMapper userMapper;

    @Autowired
    public UserServiceImpl(BCryptPasswordEncoder passwordEncoder,
                           UserMapper userMapper) {
        this.passwordEncoder = passwordEncoder;
        this.userMapper = userMapper;
    }
}

测试:

public class MyServiceTest {
    private UserMapper userMapper = Mockito.mock(UserMapper.class);
    private UserServiceImpl myService = new UserServiceImpl(userMapper);
    @Test
    public void testServiceMethod() {
        // test implementation
    }
}

优势:

  • 清晰的依赖关系:所有依赖关系在类实例化时就明确了,代码可读性和可维护性大大提高。
  • 不变性:可以使用final修饰符,确保依赖关系在对象生命周期内保持不变。
  • 便于测试:测试类只需通过构造函数注入模拟对象,简化单元测试的编写。

缺点:

  • 当注入参数较多时,代码臃肿。
  • 可能存在循环依赖问题。

解决方案:

  • 重构代码:消除循环依赖,可能成本较高。
  • 使用@Lazy注解:延迟初始化bean,解决循环依赖。
@Lazy
private final UserMapper userMapper;

五、总结

  • Spring提供三种注入方式:字段注入、setter方法注入、构造器注入。推荐使用基于构造器注入的方式。
  • 基于字段的依赖注入方式有很多缺点,主要原因是容易引发NPE,且无法在编译时期发现,应当避免使用基于字段的依赖注入。
  • 对于必需的依赖项,建议使用基于构造函数的注入,以使类成为不可变的,并防止类为null。
  • 对于可选的依赖项,建议使用基于Setter的注入。

通过采用构造器注入或设值注入,可以显著提高代码的健壮性和可测试性,避免字段注入带来的种种弊端。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端面试:项目细节重难点问题分享(十五)

更多详情:爱米的前端小笔记(csdn~xitujuejin~zhiHu~Baidu~小红shu)同步更新,等你来看!都是利用下班时间整理的,整理不易,大家多多👍💛➕🤔哦!你们…

ComfyUI 实战教程:图片添加文字

大家好,我是每天分享AI应用的萤火君! 在AI绘画中书写文字一直是个老大难的问题,直到SDXL的出现,文字生成才迎来转机,可以在提示词中指定一些英文字符,不过也是经常出错,生成中文就更加不可求了…

uView input输入框和search输入框实现搜索功能

背景&#xff1a; 在手机端实现搜索框的“查询功能”&#xff0c;使用uView组件库。有两种实现思路&#xff1a; 1.input输入框 2.search搜索框 效果展示&#xff1a; 一、search搜索框 官方文档&#xff1a;点击跳转uView官网 实际代码&#xff1a; //u-search组件 <u-se…

人生五大成熟表现

三十而立&#xff1b;立什么&#xff1f;立身、立业、立家&#xff1b; 四十不惑&#xff1b;明白了什么&#xff1f;明白了社会&#xff0c;责任、自己&#xff1b; 五十知天命&#xff1b;知道了什么&#xff1f;知道了命运轨迹&#xff0c;人生定位&#xff1b; 六十而顺&am…

58 简单学生管理系统【项目需求、数据库搭建、项目搭建、功能实现(注册功能、登录功能完善验证码功能(Session-会话对象))】

简单学生管理系统 项目需求 数据库搭建 数据库建表 导数据库sql 了解 项目搭建 导包&#xff0c;基础页面&#xff0c;实体类&#xff0c;工具类 基础页面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><ti…

深入实践,浅谈EHS管理的智能化转型

随着人工智能、大数据、云计算等先进技术的飞速发展&#xff0c;EHS管理体系与管理软件的融合正步入一个全新的智能化时代。这一转型不仅进一步提升了EHS管理的效率和精准度&#xff0c;还为企业带来了前所未有的管理视野和决策支持。 一、创新驱动&#xff0c;深化EHS管理的智…

深入探讨Google谷歌助力孟加拉slots游戏广告市场前景

深入探讨Google谷歌助力孟加拉slots游戏广告市场前景 在深入探讨孟加拉游戏广告投放于Google谷歌平台的优势时&#xff0c;不得不提及其强大的数据分析与精准定位能力。谷歌广告平台拥有全球领先的数据处理技术&#xff0c;能够基于用户的搜索历史、浏览行为、地理位置等多维度…

C语言程序设计24

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题2.1 求下列算数表达式的值 &#xff08;1&#xff09;xa%3*(int)(xy)%2/4 设x2.5,a7,y4.7 (2)(float)(ab)/2(int)x%(int)y 设 a2,b3,x3.5,y2.5 代码&#xff08;1&#xff09;&#xff1a;…

贪心系列专题篇三

目录 单调递增的数字 坏了的计算器 合并区间 无重叠区间 用最少数量的箭 声明&#xff1a;接下来主要使用贪心法来解决问题&#xff01;&#xff01;&#xff01; 单调递增的数字 题目 思路 如果我们遍历整个数组&#xff0c;然后对每个数k从[k,0]依次遍历寻找“单调递…

人力资源专家推荐:2024年十大HR软件

本篇文章介绍了以下人力资源管理工具&#xff1a;Moka、北森云计算、友人才、人瑞人才、Zoho People、金蝶之家、Gusto、Workday HCM、Namely、UKG Pro。 在选择合适的人力资源软件时&#xff0c;许多企业常常面临各种挑战&#xff0c;例如如何确保软件功能全面、用户体验良好&…

WinForm中使用Bitmap元素处理图像

前言 这个Bitmap元素在我们处理图像显示相关时&#xff0c;它的身影就可以见到了。官方术语&#xff1a;封装 GDI 位图&#xff0c;此位图由图形图像及其属性的像素数据组成。 Bitmap 是用于处理由像素数据定义的图像的对象。操作对象最重要的两个方法GetPixel和SetPixel。 一…

vscode+cmake+msys2工具链配置

1、msys2下载编译器和cmake工具 pacman -S mingw-w64-x86_64-toolchain pacman -S mingw-w64-x86_64-cmaketoolchain包中包含很多不必要的包&#xff0c;应该可以指定具体的工具g&#xff0c;gcc&#xff0c;mingw32-make的下载&#xff0c;详细命令请自行搜索。 2、将 msys2…

前端面试宝典【HTML篇】【3】

欢迎来到《前端面试宝典》,这里是你通往互联网大厂的专属通道,专为渴望在前端领域大放异彩的你量身定制。通过本专栏的学习,无论是一线大厂还是初创企业的面试,都能自信满满地展现你的实力。 核心特色: 独家实战案例:每一期专栏都将深入剖析真实的前端面试案例,从基础知…

开源=最强大模型!Llama3.1发布,405B超越闭源GPT-4o,扎克伯格:分水岭时刻

刚刚&#xff0c;LIama 3.1正式发布&#xff0c;登上大模型王座&#xff01; 在150多个基准测试集中&#xff0c;405B版本的表现追平甚至超越了现有SOTA模型GPT-4o和Claude 3.5 Sonnet。 也就是说&#xff0c;这次&#xff0c;最强开源模型即最强模型。 在此之前&#xff0c;…

零基础入门转录组数据分析——机器学习算法之xgboost(筛选特征基因)

零基础入门转录组数据分析——机器学习算法之xgboost&#xff08;筛选特征基因&#xff09; 目录 零基础入门转录组数据分析——机器学习算法之xgboost&#xff08;筛选特征基因&#xff09;1. xgboost基础知识2. xgboost&#xff08;Rstudio&#xff09;——代码实操2. 1 数据…

第N高的薪水 [sql]

CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT BEGINset N N - 1;RETURN (# Write your MySQL query statement below.select distinct salary from Employee order by salary desc limit 1 offset N); END

VSCode使用conda虚拟环境配置

如何解决CondaError: Run ‘conda init‘ before ‘conda activate‘_condaerror: run conda init before conda activat-CSDN博客 首先检查自己的anaconda是否是添加到整个的环境变量里了 打开cmd如果conda和python都能够识别那么就是配置成功了 然后看插件是否安装&#xf…

1个惊艳的Python项目火出圈,已开源,10K stars!

本次分享一个Python工具Taipy:“To build data & AI web applications in no time”。 Taipy专为数据科学家和机器学习工程师设计,用于构建数据和AI的Web应用程序。 快速构建可投入生产的Web应用程序。无需学习HTML、CSS、JS等新前端语言,只需使用Python。专注于数据和A…

抖音短视频矩阵系统优势:为何选择短视频矩阵系统?

1. 抖音短视频矩阵系统 抖音短视频矩阵系统&#xff0c;是指通过抖音平台&#xff0c;以矩阵的形式进行短视频创作、发布和传播的一种模式。它以多样化的内容、丰富的表现形式、高度的专业化和协同性&#xff0c;吸引了大量用户和创作者的关注。 2. 短视频矩阵系统的优势 2.…

jdk和tomcat的环境配置以及使用nginx代理tomcat来实现负载均衡

目录 1.jdk环境配置 1.jdk下载 2.解压 3.将jdk-22.2移动到指定目录/usr/local/jdk22/下 4.配置文件 5.运行profile 6.测试 2.tomcat环境配置 1.下载tomcat 2.解压 3.将解压后的文件移动指定目录 4.启动tomcat 5.查看端口确定是否确定成功 6.测试 7.tomcat目录 1…