Spring IoC DI 使⽤
关于 IoC 的含义,推荐看IoC含义介绍(Spring的核心思想)
喜欢 Java 的推荐点一个免费的关注,主页有更多 Java 内容
前言
通过上述的博客我们知道了 IoC 的含义,既然 Spring 是⼀个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:‘存’和‘取’
Spring容器管理的主要是对象, 这些对象, 我们称之为"Bean". 我们把这些对象交由Spring管理,我们的程序只需要告诉Spring,哪些对象需要存,以及在需要时从Spring中取出 对象
Bean的存储
要想将对象交给 Spring 进行管理,Spring 提供了丰富的注解来实现这一功能
共有两种注解类型可以实现:
1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration.(五大注解)
2. ⽅法注解:@Bean.
1.@Controller(控制器存储)
对应 Spring Web MVC 开发,三层架构中的 Controller (控制层),案例:
如下的代码,对 UserController 这个控制类加上 @Controller 注解就表明将 UserController 类的对象交给 Spring 进行管理
@Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(){System.out.println("hi,UserController");}
}
通过下面的代码来验证,我们是否成功将 UserController 类的对象交给 Spring 进行管理,SpringIocDemoApplication 是当前 Spring Web MVC 项目中的启动类,SpringApplication 是 Spring Boot框架中用于启动应用程序的类,SpringApplication 调用 run 方法启动了当前的项目,并且返回了 Spring 的 IoC 容器(也叫做 Spring 上下文),用 ApplicationContext 类型的对象 context 来接收,获得了 Spring 的 IoC 容器后,调用 getBean 方法,传入 UserController 的类对象 我们便获得了 Spring IoC 容器中管理的 UserController 类型的 对象(Bean)
@SpringBootApplication
public class SpringIocDemoApplication {public static void main(String[] args) {//获取Spring上下⽂对象 ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio//从Spring上下⽂中获取对象 UserController userController = context.getBean(UserController.class);//使⽤对象 userController.sayHi();}
}
获得 userController 对象后调用 sayHi 方法,我们便在控制台发现 sayHi 方法正确执行,代表我们成功将 UserController 类型的对象交给了 Spring 进行管理(成功将创建 UserController 对象的控制权交给了 Spring ,控制反转),并成功从 Spring 获取到对象
2.@Service(服务存储)
对应 Spring Web MVC 开发,三层架构中的 Service(业务逻辑层),案例:
如下的代码,对 UserService 这个业务逻辑类加上 @Service 注解就表明将 UserService 类的对象交给 Spring 进行管理
@Service
public class UserService {public void sayHi(String name) {System.out.println("Hi," + name);}
}
通过下面的代码来验证,我们是否成功将 UserService 类的对象交给 Spring 进行管理
@SpringBootApplication
public class SpringIocDemoApplication {public static void main(String[] args) {//获取Spring上下⽂对象 ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio//从Spring中获取UserService对象 UserService userService = context.getBean(UserService.class);//使⽤对象 userService.sayHi();}
获得 UserService 对象后调用 sayHi 方法,我们便在控制台发现 sayHi 方法正确执行,代表我们成功将 UserService 类型的对象交给了 Spring 进行管理(成功将创建 UserService 对象的控制权交给了 Spring ,控制反转)
3.五大注解总结
通过上述 @Controller 和 @Service 注解的使用以及检验,我们会发现有很多的相似之处,实际上 @Controller、@Service、@Repository、@Component、@Configuration 这五大注解的除了名称不同以外,作用都是将 对象 (Bean)交给 Spring 进行管理(将创建对象的控制权交给 Spring )(此处我们不谈这些注解在其他地方的作用,比如 @Controlle 还代表该类是一个控制类,在接收到 Http 请求后 Spring 要遍历 带有 @Controlle 注解的类)
既然 @Controller、@Service、@Repository、@Component、@Configuration 这五大注解在这里的作用都是一样的,那 Spring 为什么要提供这么多注解呢?实际上这和 Spring Web MVC 开发的三层架构对应,@Controller 这个注解对应三层架构的 Controller 控制层,@Service 对应三层架构的 Service 业务逻辑层,@Repository 对应三层架构的 Dao 数据层,不处于这三层中的类就用 @Component(组件) 注解,@Configuration 表示配置类的注解
提供 @Controller、@Service、@Repository、@Component、@Configuration 这五大注解主要是为了让程序猿针对不同层次的类用对应的注解,让程序员看到类注解之后,就能直接了解当前类的⽤途.
注意:使用五大注解,Spring 只会管理类的一个对象,无论获取这个类的对象多少次,都是同一个对象,是单例模式,那我们想要 Spring 管理一个类的多个对象的话就要看下面的方法注解@Bean
4.⽅法注解 @Bean
五大注解存在一些无法解决的问题,此时我们就需要使用方法注解,比如下面的问题:
1. 使⽤外部包⾥的类,没办法添加类注解
2. ⼀个类,需要多个对象,⽐如多个数据源
这种场景,我们就需要使⽤⽅法注解 @Bean
方法注解的使用方式如下:
根据下面的代码,我们便创建了一个类型为 User ,名称为 user 的对象交给了 Spring 管理(方法名就是 Spring 管理的对象名)
@Component
public class BeanConfig {@Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
}
注意:方法注解 @Bean 要搭配五大注解一起使用,因为 Spring 在项目运行时扫描的是加上相关注解,需要 Spring 处理的类,所以要是不加五大注解,Spring 压根就不会扫描到 @Bean 注解,也就不会管理方法创建的对象
定义多个对象
对于同⼀个类,如何定义多个对象呢? 代码如下
我们通过下面的代码便创建了两个 User 类型的对象 user1 和 user2 交给 Spring 进行管理
@Component
public class BeanConfig {@Beanpublic User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2(){User user = new User();user.setName("lisi");user.setAge(19);return user;}
}
注意:当 Spring 管理的一个类中有多个对象的时候,我们获取就不能通过类对象来获取了,要不然会报错,我们可以通过对象(Bean)的名称或者对象(Bean) 的名称加类型来从 Spring 那里获取指定的对象
通过 getBean 方法获取对象的三种常用参数
@SpringBootApplication2
public class SpringIocDemoApplication {
public static void main(String[] args) {
//获取Spring上下⽂对象
ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//从Spring上下⽂中获取对象
//根据bean类型, 从Spring上下⽂中获取对象
UserController userController1 = context.getBean(UserController.class);
//根据bean名称, 从Spring上下⽂中获取对象
UserController userController2 = (UserController)context.getBean("userController");
//根据bean名称+类型, 从Spring上下⽂中获取对象
UserController userController3 = context.getBean("userController",UserController.class);}
}
Bean(对象) 的重命名
根据上面的介绍我们知道,使用 @Bean 注解让 Spring 管理方法创建的对象时,对象的名称就是方法名称,那我们可不可以修改 Spring 管理的对象名称呢?那必然是可以的
通过在 @Bean 注解中设置属性 name 来重命名对象名称,如下的方式为该对象设置了两个名称,所以我们查找名称 u1 和 user1 都是这个对象
@Bean(name = {"u1","user1"})
public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;
}
而如果一个对象就一个名称的话,重命名就更加的简单,直接在 @Bean 注解中加上要修改的名称即可
@Bean("u1")
public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;
}
Bean的获取
Bean的获取就是获取 Spring 管理的对象,也可以叫做依赖注⼊DI,简单来说,就是把对象取出来放到某个类的属性中
关于依赖注⼊,Spring也给我们提供了三种⽅式:
1. 属性注⼊(Field Injection)
2. 构造⽅法注⼊(Constructor Injection)
3. Setter 注⼊(Setter Injection)
1. 属性注⼊
属性注⼊是使⽤注解 @Autowired 实现的
如下代码,UserController 类中有 UserService 类型的属性需要赋值,在 UserService 类型的属性前加上 @Autowired 注解,表明要从 Spring 那里获取到 UserService 类型的对象赋值给 userService 变量
public class UserController {//注⼊⽅法1: 属性注⼊ @Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}
}
2.构造⽅法注⼊
构造⽅法注⼊是在类的构造⽅法中实现注⼊,如下代码所⽰:
在构造方法前加上 @Autowired 注解,表明要从 Spring 那里获取到构造方法的参数,此时构造方法需要 UserService 类型的对象,便会从 Spring 那里获取到,完成构造方法
public class UserController2 {//注⼊⽅法2: 构造⽅法 private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}
}
注意:如果类只有⼀个构造⽅法,那么 @Autowired 注解可以省略;如果类中有多个构造⽅法, 那么需要添加上 @Autowired 来明确指定到底使⽤哪个构造⽅法。
3.Setter 注⼊
Setter 注⼊和属性的 Setter ⽅法实现类似,只不过在设置 set ⽅法的时候需要加 @Autowired 注 解 ,如下代码所⽰:
在 set 方法前加上 @Autowired 注解就表示要从 Spring 那里获取到 set 方法的参数
@Controller
public class UserController3 {//注⼊⽅法3: Setter⽅法注⼊ private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}
}
三种注⼊的优缺点分析
1.属性注⼊
◦ 优点: 简洁,使⽤⽅便;
◦ 缺点: ▪ 1.只能⽤于 IoC 容器,如果是⾮ IoC 容器不可⽤,并且只有在使⽤的时候才会出现 NPE(空 指针异常)
▪ 不能注⼊⼀个Final修饰的属性
2.构造函数注⼊(Spring4.X推荐)
◦ 优点: ▪ 1.可以注⼊final修饰的属性
▪ 2.注⼊的对象不会被修改
▪ 3.依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅ 法是在类加载阶段就会执⾏的⽅法。
▪ 4.通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
◦ 缺点: ▪ 注⼊多个对象时,代码会⽐较繁琐
3.Setter注⼊(Spring 3.X推荐)
◦ 优点 ⽅便在类实例之后,重新对该对象进⾏配置或者注⼊ ◦ 缺点:
▪ 1.不能注⼊⼀个Final修饰的属性
▪ 2.注⼊对象可能会被改变,因为setter⽅法可能会被多次调⽤,就有被修改的⻛险.
@Autowired存在问题
当同⼀类型存在多个 bean(对象) 时, 使⽤ @Autowired 会存在问题,因为 Spring 不知道你要获取该类型的哪个对象
假设 Spring 中管理了 UserService 类型的多个对象,此时在一个类中有 UserService 类型的属性,并且加上了 @Autowired 注解表明要从 Spring 那里获取属性的值,此时 Spring 会先进行名称匹配,要是属性的名称和 Spring 那里管理的对象名称相同,那 Spring 就知道此时要获取哪个对象了,但要是名称都不同,就会报错
如何解决上述问题呢?
Spring提供了以下⼏种解决⽅案:
• @Primary
• @Qualifier
• @Resource
@Primary
如下代码,要将 User 类型的 user1 和 user2 对象交给 Spring 进行管理,在 user1 方法前加上 @Primary 注解,就表明了 user1 是主要的对象,这样在不明确程序需要获取 User 类型的哪个对象的时候,Spring 就会提供 user1 对象
@Component
public class BeanConfig {@Primary //指定该bean为默认bean的实现 @Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}@Beanpublic User user2() {User user = new User();user.setName("lisi");user.setAge(19);return user;}
}
注意:但是实际上这个方法并不常用,因为要是设置了主要的对象,那么大多数情况下使用的都只会是主要的那个对象,该类型其他对象的存在就没有必要了
@Qualifier
指定当前要注⼊的bean对象。在 @Qualifier 的value属性中,指定注⼊的 bean 的名称。
如下代码,加上注解 @Qualifier("user2") 就代表要获取 Spring 管理的名称为 user2 的对象注入到属性 user 中
public class UserController {@Qualifier("user2") //指定bean名称 @Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}
}
注意: @Qualifier 注解不能单独使⽤,必须配合 @Autowired 使⽤
@Resource
是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。
如下代码,加上注解 @Resource(name = "user2") 就代表要获取 Spring 管理的名称为 user2 的对象注入到属性 user 中
public class UserController {@Resource(name = "user2")private User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}
}
@Autowird 与 @Resource 的区别
@Autowired 是spring框架提供的注解,⽽@Resource是JDK提供的注解
@Autowired 默认是按照类型注⼊,⽽ @Resource 是按照名称注⼊( @Autowired 搭配@Qualifier 也可以按照名称注入)
相关文章:
Spring IoC DI 使⽤
关于 IoC 的含义,推荐看IoC含义介绍(Spring的核心思想) 喜欢 Java 的推荐点一个免费的关注,主页有更多 Java 内容 前言 通过上述的博客我们知道了 IoC 的含义,既然 Spring 是⼀个 IoC(控制反转)…...

Zigbee智能家居方案设计
背景 目前智能家居物联网中最流行的三种通信协议,Zigbee、WiFi以及BLE(蓝牙)。这三种协议各有各的优势和劣势。本方案基于CC2530芯片来设计,CC2530是TI的Zigbee芯片。 网关使用了ESP8266CC2530。 硬件实物 节点板子上带有继电器…...

机器视觉目标检测 - opencv 深度学习 计算机竞赛
文章目录 0 前言2 目标检测概念3 目标分类、定位、检测示例4 传统目标检测5 两类目标检测算法5.1 相关研究5.1.1 选择性搜索5.1.2 OverFeat 5.2 基于区域提名的方法5.2.1 R-CNN5.2.2 SPP-net5.2.3 Fast R-CNN 5.3 端到端的方法YOLOSSD 6 人体检测结果7 最后 0 前言 ǵ…...

无监督学习的集成方法:相似性矩阵的聚类
在机器学习中,术语Ensemble指的是并行组合多个模型,这个想法是利用群体的智慧,在给出的最终答案上形成更好的共识。 这种类型的方法已经在监督学习领域得到了广泛的研究和应用,特别是在分类问题上,像RandomForest这样…...
16. 机器学习——决策树
机器学习面试题汇总与解析——决策树 本章讲解知识点 什么是决策树决策树原理决策树优缺点决策树的剪枝决策树的改进型本专栏适合于Python已经入门的学生或人士,有一定的编程基础。 本专栏适合于算法工程师、机器学习、图像处理求职的学生或人士。 本专栏针对面试题答案进行了…...
DevOps系列---【jenkinsfile使用sshpass发送到另一台服务器】
1.首先在宿主机安装sshpass 2.把物理机的sshpass复制到容器中 which sshpass cp $(which sshpass) /usr/local/app/ docker cp sshpass 容器id:/usr/local/bin/sshpass 3.在jenkinsfile中添加 #在stages中添加stage stage(部署TEST服务){steps{sh "sshpass -p root1234 sc…...

Docker 和 Kubernetes:技术相同和不同之处
Docker和Kubernetes是当今最流行的容器化技术解决方案。本文将探讨Docker和Kubernetes的技术相似之处和不同之处,以帮助读者更好地理解这两种技术。 Docker和Kubernetes:当今最流行的容器化技术解决方案 在当今的IT领域,Docker和Kubernetes无…...

通信世界扫盲基础二(原理部分)
上次我们刚学习了关于通信4/G的组成和一些通识,今天我们来更深层次了解一些原理以及一些新的基础~ 目录 专业名词 LTE(4G系统) EPC s1 E-UTRAN UE UU X2 eNodeB NR(5G系统) NGC/5GC NG NG-RAN Xn gNodeB N26接口 手机的两种状态 空闲态 连接态 …...

手机厂商参与“百模大战”,vivo发布蓝心大模型
在2023 vivo开发者大会上,vivo发布自研通用大模型矩阵——蓝心大模型,其中包含十亿、百亿、千亿三个参数量级的5款自研大模型,其中,10亿量级模型是主要面向端侧场景打造的专业文本大模型,具备本地化的文本总结、摘要等…...
【微软技术栈】C#.NET 中的泛型
本文内容 定义和使用泛型泛型的利与弊类库和语言支持嵌套类型和泛型 借助泛型,你可以根据要处理的精确数据类型定制方法、类、结构或接口。 例如,不使用允许键和值为任意类型的 Hashtable 类,而使用 Dictionary<TKey,TValue> 泛型类并…...

【毕业论文】基于微信小程序的植物分类实践教学系统的设计与实现
基于微信小程序的植物分类实践教学系统的设计与实现https://download.csdn.net/download/No_Name_Cao_Ni_Mei/88519758 基于微信小程序的植物分类实践教学系统的设计与实现 Design and Implementation of Plant Classification Practical Teaching System based on WeChat Mini…...

[量化投资-学习笔记011]Python+TDengine从零开始搭建量化分析平台-MACD金死叉策略回测
在上一章节 MACD金死叉中结束了如何根据 MACD 金死叉计算交易信号。 目录 脚本说明文档(DevChat 生成)MACD 分析脚本安装依赖库参数配置查询与解析数据计算 MACD 指标判断金叉和死叉计算收益绘制图形运行脚本 本次将根据交易信号,模拟交易。更…...

tensorboard报错解决:No dashboards are active for the current data set
版本:tensorboard 2.10.0 问题:文件夹下明明有events文件,但用tensorboard命令却无法显示。 例如: 原因:有可能是文件路径太长了,导致系统无法读取文件。在win系统中规定,目录的绝对路径不得超…...

线性代数本质系列(一)向量,线性组合,线性相关,矩阵
本系列文章将从下面不同角度解析线性代数的本质,本文是本系列第一篇 向量究竟是什么? 向量的线性组合,基与线性相关 矩阵与线性相关 矩阵乘法与线性变换 三维空间中的线性变换 行列式 逆矩阵,列空间,秩与零空间 克莱姆…...
python语法之注释
注释可用于解释Python代码。 注释可用于使代码更易读。 注释可用于在测试代码时阻止执行。 (1)创建注释 注释以#开头,Python会忽略它们: #This is a comment print("Hello, World!") 注释可以放在一行…...

React【异步逻辑createAsyncThunk(一)、createAsyncThunk(二)、性能优化、createSelector】(十二)
文章目录 异步逻辑 createAsyncThunk(一) createAsyncThunk(二) 性能优化 createSelector 异步逻辑 //Product.js const onAdd () > {const name nameRef.current.value// 触发添加商品的事件dispatch(addProduct({name…...

Halcon WPF 开发学习笔记(3):WPF+Halcon初步开发
文章目录 前言在MainWindow.xaml里面导入Halcon命名空间WPF简单调用Halcon创建矩形简单调用导出脚本函数 正确显示匹配效果 前言 本章会简单讲解如何调用Halcon组件和接口,因为我们是进行混合开发模式。即核心脚本在平台调试,辅助脚本C#直接调用。 在M…...

P6入门:项目初始化9-项目详情之资源 Resource
前言 使用项目详细信息查看和编辑有关所选项目的详细信息,在项目创建完成后,初始化项目是一项非常重要的工作,涉及需要设置的内容包括项目名,ID,责任人,日历,预算,资金,分类码等等&…...

Python高级语法----使用Python进行模式匹配与元组解包
文章目录 1. 模式匹配的新特性2. 高级元组解包技巧3. 数据类的匹配与应用1. 模式匹配的新特性 Python自3.10版本起引入了结构化模式匹配的新特性,这是一种强大的工具,允许开发者用更清晰、更直观的方式处理数据结构。模式匹配类似于其他编程语言中的switch-case语句,但它更…...
MySQL安装配置与使用教程(2023.11.13 MySQL8.0.35)
CONTENTS 1. MySQL的安装与配置2. MySQL常用操作教程 1. MySQL的安装与配置 MySQL Windows Installer 下载地址:MySQL Installer。 我们下载最新版本(目前是8.0.35)的安装包,注意要选择更大的那个,名字为 mysql-inst…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...