当前位置: 首页 > news >正文

DI依赖注入详解

DI依赖注入

声明了一个成员变量(对象)之后,在该对象上面加上注解@AutoWired注解,那么在程序运行时,该对象自动在IOC容器中寻找对应的bean对象,并且将其赋值给成员变量,完成依赖注入。

@AutoWired依赖注入的常见方式

1.属性注入

直接使用@AutoWired进行属性注入:

@Autowired
private UserService userService;

这是最简单的依赖注入方式,其优点是:代码简洁,可以方便快速的开发。其缺点是:直接使用属性注入,隐藏了各类之间的依赖关系:Controller是依赖了Service的,但是在类的结构层面无法看出二者的关联。还有可能会破坏类的封装性:按照封装性的解释来看,我们需要将成员属性设置为私有,并对外提供对应的set/get方法;但是直接使用属性注入,没有对外提供set方法,直接对其赋值,在底层是通过反射对其进行赋值的,实际上是破坏了面向对象的封装性原则的。

2.构造函数注入

通过构造函数的方式完成对成员变量的依赖注入:

private final UserService userService;
@Autowired
public UserController(UserService userService) {this.userService = userService;
}

相对于属性注入而言,构造函数注入就能够清晰的看到各类之间的依赖关系,并且基于构造函数注入,可以将userService设置为final,更加安全。但是假如是该类依赖了多个其他的类,都交给IOC容器管理,那么在书写构造方法注入的时候,构造方法的参数将十分多,构造方法将十分臃肿。

注意:如果该类只有一个构造函数,那么该构造函数上的@Autowired注解可以省略

3.setter注入

通过set方法完成对成员变量的依赖注入:

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

优点和构造方法注入类似(但是不能将成员变量设置为final),缺点是需要额外提供set方法,编码繁琐。这种setter注入在开发中基本上不会使用。

在项目开发中,Spring官方推荐构造函数注入,因为其很好的保证了面向对象的特性,并且安全性得到很好的保障;但是在开发中大部分项目都喜欢使用属性注入,因为其简洁、方便开发。所以说要根据项目的具体要求而判断,在简洁性和规范性之间进行取舍。(setter注入基本不用)

使用@AutoWired注解的注意事项

类型注入

@Autowired注解在进行依赖注入时,默认是依据类型进行注入操作。然而,倘若存在需要注入的对象有多个对应的 bean实例时,就会引发错误:

这是第一个UserService的bean

package com.wzb.service.impl;import com.wzb.dao.UserDao;
import com.wzb.pojo.User;
import com.wzb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;/*** Service层实现类**/
@Component("newName")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;// 获取用户数据的代码不能写在此处,类的成员变量初始化是在类的实例化阶段进行的,此时可能@AutoWired注入还未完成,导致Null// private final List<String> lines = userDao.findUser();public List<User> findUser() {List<String> lines = userDao.findUser();List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]);String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());return userList;}
}

这是第二个UserService对象的bean

package com.wzb.service.impl;import com.wzb.dao.UserDao;
import com.wzb.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;/*** 用于测试用的bean* */
@Component
public class UserServiceImpl2 implements UserService{@Autowiredprivate UserDao userDao;public List<User> findUser() {List<String> lines = userDao.findUser();List<User> userList = lines.stream().map(line -> {String[] parts = line.split(",");Integer id = Integer.parseInt(parts[0]) + 200;String username = parts[1];String password = parts[2];String name = parts[3];Integer age = Integer.parseInt(parts[4]);LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));return new User(id, username, password, name, age, updateTime);}).collect(Collectors.toList());return userList;}
}

此时Controller中需要依赖UserService这个类,但是IOC容器中有两个这个对象的bean,此时如果直接启动,程序将会直接报错:

 报错信息:

根据报错信息的描述来看,是因为UserController需要一个bean(也就是UserService的实现类),但是在IOC容器中找到了两个该对象的bean实例,不知道应该注入哪一个,所以说就报错了。并且还在Action中提供了一个解决方法:使用@Primary、@Qualifier注解。这证明了不能直接将同一个对象的多个bean加入IOC容器管理,如果一个对象有多个bean都需要给IOC容器管理,那么就需要使用其他注解,来成功找到需要的bean并注入。

解决方法

@Primary

假如需要注入的对象在IOC容器中存在多个bean实例,那么就可以在想要被注入的bean上添加注解@Primary:

使用@Primary注解,指定注入的UserService bean实例是UserServiceImpl2,将服务启动结合前端页面查看结果:

 

 

发现用户的id都加了200,说明此时注入的UserService实例bean是UserServiceImpl2,@Primary注解成功指定了注入的bean实例。

@Qualifier

@Qualifier注解需要配合@AutoWired注解使用,@Qualifier注解是在声明对象时使用,可以通过注解名(默认是类名小写)指定需要注入的bean实例对象。

通过@Qualifier注解和@AutoWired注解结合使用,指定需要注入UserService的bean实例是UserServiceImpl(注意,bean名字是类名小写):

 

 

发现通过@Qualifier注解和@AutoWired注解结合使用,成功将UserService需要注入的bean实例指定为了UserServiceImpl。

重要一点

此时UserServiceImpl2上面的@Primary注解还在,但是注入的是UserServiceImpl,说明@Qualifiler的优先级高于@Primary。

@Resource

@Resource注解是在声明对象时使用,单独使用,通过注解名指定需要注入的bean实例:

@Resource注解不是Spring提供的,是JavaEE规范中提供的,使用时需要指定name = "bean名",同样,此时UserServiceImpl2的@Primary注解还在,但是注入的是@Resource注解指定的bean实例,所以说@Resource注解的优先级也高于@Primary注解。

但是假如将@Resource和@Qualifier注解一起用:

 

 

其注入的bean是@Resource注解指定的,说明@Resource的优先级高于@Qualifier;可能是因为原生JavaEE的优先级高于SpringBoot框架的缘故。

@Resource和@AutoWired都可以实现依赖注入,其二者区别主要有两点:1.@AutoWired是Spring框架提供的,而@Resource是JavaEE提供的,二者的出处不同;2.@AutoWired是默认按照类型注入的,但@Resource是默认按照bean的名称进行注入的。

总的而言,假如说一个类在IOC容器中存在多个bean实例,那么无法直接使用,因为不知道该选择哪个bean进行注入,需要添加注解指定需要注入哪个bean。

相关文章:

DI依赖注入详解

DI依赖注入 声明了一个成员变量&#xff08;对象&#xff09;之后&#xff0c;在该对象上面加上注解AutoWired注解&#xff0c;那么在程序运行时&#xff0c;该对象自动在IOC容器中寻找对应的bean对象&#xff0c;并且将其赋值给成员变量&#xff0c;完成依赖注入。 AutoWire…...

TDengine在debian安装

参考官网文档&#xff1a; 官网安装文档链接 从列表中下载获得 Deb 安装包&#xff1b; TDengine-server-3.3.4.3-Linux-x64.deb (61 M) 进入到安装包所在目录&#xff0c;执行如下的安装命令&#xff1a; sudo dpkg -i TDengine-server-<version>-Linux-x64.debNOTE 当…...

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …...

XGBoost库介绍:提升机器学习模型的性能

XGBoost库介绍&#xff1a;提升机器学习模型的性能 在机器学习领域&#xff0c;模型的准确性和训练效率是最为关注的两大因素。特别是在处理大量数据和复杂任务时&#xff0c;传统的机器学习算法可能无法满足高效和准确性的需求。XGBoost&#xff08;eXtreme Gradient Boostin…...

网络安全构成要素

一、防火墙 组织机构内部的网络与互联网相连时&#xff0c;为了避免域内受到非法访问的威胁&#xff0c;往往会设置防火墙。 使用NAT&#xff08;NAPT&#xff09;的情况下&#xff0c;由于限定了可以从外部访问的地址&#xff0c;因此也能起到防火墙的作用。 二、IDS入侵检…...

SpringMVC——SSM整合

SSM整合 创建工程 在pom.xml中导入坐标 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_…...

Windows系统电脑安装TightVNC服务端结合内网穿透实现异地远程桌面

文章目录 前言1. 安装TightVNC服务端2. 局域网VNC远程测试3. Win安装Cpolar工具4. 配置VNC远程地址5. VNC远程桌面连接6. 固定VNC远程地址7. 固定VNC地址测试 前言 在追求高效、便捷的数字化办公与生活的今天&#xff0c;远程桌面服务成为了连接不同地点、不同设备之间的重要桥…...

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda...

Spring Boot 动态数据源切换

背景 随着互联网应用的快速发展&#xff0c;多数据源的需求日益增多。Spring Boot 以其简洁的配置和强大的功能&#xff0c;成为实现动态数据源切换的理想选择。本文将通过具体的配置和代码示例&#xff0c;详细介绍如何在 Spring Boot 应用中实现动态数据源切换&#xff0c;帮…...

MySQL技巧之跨服务器数据查询:进阶篇-从A服务器的MySQ数据库复制到B服务器的SQL Server数据库的表中

MySQL技巧之跨服务器数据查询&#xff1a;进阶篇-从A服务器的MySQ数据库复制到B服务器的SQL Server数据库的表中 基础篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MyS…...

大语言模型LLM的微调中 QA 转换的小工具 xlsx2json.py

在训练语言模型中&#xff0c;需要将文件整理成规范的文档&#xff0c;因为文档本身会有很多不规范的地方&#xff0c;为了训练的正确&#xff0c;将文档进行规范处理。代码的功能是读取一个 Excel 文件&#xff0c;将其数据转换为 JSON 格式&#xff0c;并将 JSON 数据写入到一…...

CFD 在生物反应器放大过程中的作用

工艺工程师最常想到的一个问题是“如何将台式反应器扩大到工业规模的反应器&#xff1f;”。这个问题的答案并不简单&#xff0c;也不容易得到。例如&#xff0c;人们误以为工业规模的反应器的性能与台式反应器相同。因此&#xff0c;扩大规模的过程并不是一件容易的事。必须对…...

Axios与FastAPI结合:构建并请求用户增删改查接口

在现代Web开发中&#xff0c;FastAPI以其高性能和简洁的代码结构成为了构建RESTful API的热门选择。而Axios则因其基于Promise的HTTP客户端特性&#xff0c;成为了前端与后端交互的理想工具。本文将介绍FastAPI和Axios的结合使用&#xff0c;通过一个用户增删改查&#xff08;C…...

美畅物联丨如何通过ffmpeg排查视频问题

在我们日常使用畅联AIoT开放云平台的过程中&#xff0c;摄像机视频无法播放是较为常见的故障。尤其是当碰到摄像机视频不能正常播放的状况时&#xff0c;哪怕重启摄像机&#xff0c;也仍然无法使其恢复正常的工作状态&#xff0c;这着实让人感到头疼。这个时候&#xff0c;可以…...

基于OpenCV视觉库让机械手根据视觉判断物体有无和分类抓取的例程

项目实例&#xff0c;在一个无人封闭的隔绝场景中&#xff0c;根据视觉判断物件的有无&#xff0c;通过机械手 进行物件分类提取&#xff0c;并且返回状态结果&#xff1b; 实际的场景是有一个类似采血的固件支架盘&#xff0c;上面很多采血管&#xff0c;采血管帽颜色可能不同…...

QChart数据可视化

目录 一、QChart基本介绍 1.1 QChart基本概念与用途 1.2 主要类的介绍 1.2.1 QChartView类 1.2.2 QChart类 1.2.3QAbstractSeries类 1.2.4 QAbstractAxis类 1.2.5 QLegendMarker 二、与图表交互 1. 动态绘制数据 2. 深入数据 3. 缩放和滚动 4. 鼠标悬停 三、主题 …...

转换的艺术:如何在JavaScript中序列化Set为Array、Object及逆向操作

先认识一下Set 概念&#xff1a;存储唯一值的集合&#xff0c;元素只能是值&#xff0c;没有键与之对应。Set中的每个值都是唯一的。 特性&#xff1a; 值的集合&#xff0c;值可以是任何类型。 值的唯一性&#xff0c;每个值只能出现一次。 保持了插入顺序。 不支持通过索引来…...

万能门店小程序管理系统存在前台任意文件上传漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

详解Rust泛型用法

文章目录 基础语法泛型与结构体泛型约束泛型与生命周期泛型与枚举泛型和Vec静态泛型(const 泛型)类型别名默认类型参数Sized Trait与泛型常量函数与泛型泛型的性能 Rust是一种系统编程语言&#xff0c;它拥有强大的泛型支持&#xff0c;泛型是Rust中用于实现代码复用和类型安全…...

移远通信携手紫光展锐,以“5G+算力”共绘万物智联新蓝图

11月26日&#xff0c;2024紫光展锐全球合作伙伴大会在上海举办。作为紫光展锐重要的合作伙伴&#xff0c;移远通信应邀参会。 在下午的物联网生态论坛上&#xff0c;移远通信产品总监胡勇华作题为“5G与算力双擎驱动 引领智联新未来”的演讲&#xff0c;深度剖析了产业发展的趋…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...