详解Spring IoCDI(二)
目录
承接上文:详解Spring IoC&DI (一)
1.IoC详解
1.1方法注解@Bean
1.2方法注解要配合类注解使用
1.3定义多个对象
1.4重命名Bean
1.5扫描路径
2.DI详解
2.1DI与IoC的关系
2.2属性注入
2.3构造方法注入
2.4Setter注入
2.5 三种注入优缺点分析
2.6Autowired存在问题
2.6.1Primary
2.6.2Qualifier
2.6.3Resource
承接上文:详解Spring IoC&DI (一)
1.IoC详解
1.1方法注解@Bean
类注解是添加到某个类上的 , 但是存在两个问题:
1.使⽤外部包⾥的类, 没办法添加类注解
2.⼀个类, 需要多个对象, 比如多个数据源
这种场景, 我们就需要使⽤⽅法注解@Bean
代码示例:
public class BeanConfig { @Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}}
当我们写完以上代码 ,尝试获取 bean 对象中的 user 时却发现 ,根本获取不到:
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//从Spring上下⽂中获取对象User user =context.getBean(User.class);//使⽤对象System.out.println(user);}
}
执行结果如下:
1.2方法注解要配合类注解使用
在 Spring 框架的设计中 ,⽅法注解 @Bean 要配合类注解才能将对象正常的存储到Spring 容器中
如下代码所示:
@Componentpublic class BeanConfig { @Beanpublic User user(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}}
再次执⾏以上代码 ,运⾏结果如下:
1.3定义多个对象
多数据源的场景, 类是同⼀个, 但是配置不同, 指向不同的数据源.
@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(28);return user;}}
获取对象:
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class, args);//从Spring上下⽂中获取对象User user1 = (User) context.getBean("user1");User user2 = (User) context.getBean("user2");//使⽤对象System.out.println(user1);System.out.println(user2);}
}
运行结果:
1.4重命名Bean
可以通过设置 name 属性给 Bean 对象进⾏重命名操作 ,如下代码所示:
@Bean(name = {"u1","user1"})public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
此时我们使用u1就可以获取到User对象:
User u1 = (User) context.getBean("u1");
name={} 可以省略 ,如下代码所⽰:
@Bean({"u1","user1"})public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
只有⼀个名称时, {}也可以省略, 如:
@Bean("u1")public User user1(){User user = new User();user.setName("zhangsan");user.setAge(18);return user;}
1.5扫描路径
使⽤前⾯学习的四个注解声明的bean想要⽣效 ,还需要被Spring扫描
通过修改项目工程的目录结构进行测试:
运行结果:
解释: 没有bean的名称为u1,
使⽤五⼤注解声明的bean ,要想⽣效, 还需要配置扫描路径, 让Spring扫描到这些注解也就是通过
@ComponentScan来配置扫描路径.
@ComponentScan({"com.example.demo"})
@SpringBootApplication
public class TestSpringTwoApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//从Spring上下⽂中获取对象User user =context.getBean(User.class);//使⽤对象System.out.println(user);}
}
@ComponentScan注解虽然没有显式配置,但是实际已经包含在了启动类声明注解
@SpringBootApplication中了,默认扫描的范围是启动类所在包及其子包
2.DI详解
2.1DI与IoC的关系
DI(Dependency Injection,依赖注入)和 IoC(Inversion of Control,控制反转)有着密切的关系。 可以说 DI 是实现 IoC 的一种具体方式。 IoC 是一种设计思想,强调将对象之间的控制权进行反转,不再由对象自己去创建或获取其依赖,而是由外部(如框架)来控制和管理依赖关系的创建和注入。 而 DI 则侧重于具体的将依赖对象注入到目标对象的操作,它是实现 IoC 理念的重要手段之一。通过 DI,依赖对象在合适的时候被准确地注入到需要它们的对象中,从而体现了 IoC 的原则。 简单来说,IoC 是更宏观的概念,DI 是实现 IoC 的具体策略和机制。
关于依赖注⼊, Spring也给我们提供了三种⽅式:
属性注⼊(Field Injection)、构造⽅法注⼊(Constructor Injection)、Setter 注⼊(Setter Injection)
2.2属性注入
@SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //获取Spring上下⽂对象ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio //从Spring上下⽂中获取对象UserController userController = (UserController) context.getBean("userCont //使⽤对象userController.sayHi(); 11 }}
属性注⼊是使用@Autowired实现的 ,将 Service 类注⼊到 Controller 类中.
Service类的实现代码如下:
import org.springframework.stereotype.Service; @Servicepublic class UserService {public void sayHi() {System.out.println("Hi,UserService");}}
Controller 类的实现代码如下:
@Controllerpublic class UserController { //注⼊⽅法1: 属性注⼊@Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}}
获取Controller中的sayHi方法:
@SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //获取Spring上下⽂对象ApplicationContext context = SpringApplication.run(TestSpringTwoApplication.class,args);//从Spring上下⽂中获取对象UserController userController = context.getBean(UserController.class);//使⽤对象userController.sayHi(); }}
运行结果为:
2.3构造方法注入
构造方法注入是在类的构造方法中实现注入,如下代码所示:
@Controller
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 来明确指定到底使⽤哪个构造⽅法。
2.4Setter注入
Setter 注⼊和属性的 Setter 方法实现类似 ,只不过在设置 set 方法的时候需要加上@Autowired 注解 ,如下代码所示:
@Controllerpublic class UserController3 { //注⼊⽅法3: Setter⽅法注⼊private UserService userService; @Autowiredpublic void setUserService(UserService userService) {this.userService = userService;} public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}}
2.5 三种注入优缺点分析
属性注⼊
优点: 简洁 ,使⽤⽅便;
缺点:只能⽤于 IoC 容器 ,并且只有在使⽤的时候才会出现 NPE( 空指针异常)、 不能注入⼀个Final修饰的属性
构造函数注⼊(Spring 4.X推荐)
优点:可以注⼊final修饰的属性、注⼊的对象不会被修改、依赖对象在使⽤前⼀定会被完全初始化 ,因为依赖是在类的构造⽅法中执⾏的 ,⽽构造⽅法是在类加载阶段就会执⾏的⽅法、 通⽤性好, 构造⽅法是JDK⽀持的, 所以更换任何框架,他都是适⽤的
缺点: 注入多个对象时, 代码会比较繁琐
Setter注⼊(Spring 3.X推荐)
优点: ⽅便在类实例之后, 重新对该对象进⾏配置或者注⼊
缺点:不能注⼊⼀个Final修饰的属性、注⼊对象可能会被改变, 因为setter⽅法可能会被多次调⽤ , 就有被修改的风险.
2.6Autowired存在问题
当同⼀类型存在多个bean时, 使⽤@Autowired会存在问题
@Componentpublic class BeanConfig { @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;}}
@Controllerpublic class UserController { //注⼊user @Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();System.out.println(user);}}
运行结果:
报错的原因是 ,⾮唯—的 Bean 对象。
Spring提供了以下几种解决⽅案:
2.6.1Primary
@Primary注解: 当存在多个相同类型的Bean注⼊时 ,加上@Primary注解 ,来确定默认的实现.
@Componentpublic 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;}}
2.6.2Qualifier
指定当前要注⼊的bean对象。 在@Qualifier的value属性中 ,指定注⼊的bean 的名称。
@Qualifier注解不能单独使⽤ ,必须配合@Autowired使用
@Controllerpublic class UserController {@Qualifier("user2") //指定bean名称@Autowiredprivate User user;public void sayHi(){System.out.println("hi,UserController...");System.out.println(user);}}
2.6.3Resource
使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。
@Controllerpublic 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 来说, @Resource ⽀持更多的参数设置 ,例如 name 设置 ,根据名称获取 Bean。
相关文章:

详解Spring IoCDI(二)
目录 承接上文:详解Spring IoC&DI (一) 1.IoC详解 1.1方法注解Bean 1.2方法注解要配合类注解使用 1.3定义多个对象 1.4重命名Bean 1.5扫描路径 2.DI详解 2.1DI与IoC的关系 2.2属性注入 2.3构造方法注入 2.4Setter注入 2.5 三…...

说明白计算机网络之TCP的流量控制与拥塞控制之慢开始算法与拥塞避免算法
TCP的流量控制 利用滑动窗口实现流量控制 设A向B发送数据,连接建立时候,B告诉A自身的接收窗口大小,A的发送窗口大小不能超过接收方B的窗口大小 流量控制:发送方发送速率不要太快,要让接收方来得及接收。窗口大小的单…...

这款信创FTP软件,可实现安全稳定的文件传输
信创,即信息技术应用创新,2018年以来,受“华为、中兴事件”影响,国家将信创产业纳入国家战略,并提出了“28n”发展体系。“8”具体指金融、石油、电力、电信、交通、航空航天、医院、教育等主要行业。目前企业使用比较…...

代码随想录算法训练营第十天|232.用栈实现队列、225. 用队列实现栈
232.用栈实现队列 题目链接:232. 用栈实现队列 文档讲解:代码随想录 状态:写出来 ,但差强人意 思路: 定义两个容器,可以是Stack,也可以是Deque,stackIn相当于临时容器,用来存放元素&…...

STM32 IIC协议
本文代码使用 HAL 库。 文章目录 前言一、什么是IIC协议二、IIC信号三、IIC协议的通讯时序1. 写操作2. 读操作 四、上拉电阻作用总结 前言 从这篇文章开始为大家介绍一些通信协议,包括 UART,SPI,IIC等。 UART串口通讯协议 SPI通信协议 一、…...
Java生成随机数的几种方式
随机数,在一些特殊场景下,是非常常用的。比如一些测试和验证场景、安全加密、随机抽样等都有随机数的‘身影’。 一、 使用java.util.Random类 java.util.Random类提供了更全面的随机数生成功能,包括随机整数、随机浮点数、随机布尔值等。 p…...
【面试】什么是Java虚拟机
目录 1. 说明2. 关键点 1. 说明 1.Java虚拟机(Java Virtual Machine,简称JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境。2.JVM是Java平台无关性的关键,它允许Java程序在任何支持JVM的硬件和操作系统上运…...
Go 语言的基本构成、要素与编写规范
Go 语言,作为由 Google 开发的现代编程语言,以其简洁、高效和并发编程能力而著称。在构建高性能分布式系统和现代软件开发中,Go 语言正日益受到欢迎。本篇文章将详细探讨 Go 语言程序结构的各个要素,包括函数定义、注释规范、数据…...

从了解到掌握 Spark 计算框架(二)RDD
文章目录 RDD 概述RDD 组成RDD 的作用RDD 算子分类RDD 的创建1.从外部数据源读取2.从已有的集合或数组创建3.从已有的 RDD 进行转换 RDD 常用算子大全转换算子行动算子 RDD 算子综合练习RDD 依赖关系窄依赖宽依赖宽窄依赖算子区分 RDD 血统信息血统信息的作用血统信息的组成代码…...

香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试(三)
整期笔记索引 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试(一) 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试(二) 香橙派OrangePi AIpro上手笔记——之USB摄像头目标检测方案测试(…...
【git】常用命令
删除 删除本地分支: // 删除本地分支 git branch -d localBranchName 删除远程仓库分支 git push origin --delete <branch_name> 验证远程分支是否删除 git fetch -p //会清理已经删除的远端分支的引用 git branch -r //列出所有远端分支࿰…...

JavaWeb_MySQL数据库
数据库: MySQL数据模型: MySQL是关系型数据库。 SQL: 简介 分类: 数据库设计-DDL 对数据库操作: 表操作: 小练习: 创建下表 SQL代码: create table tb_user (id int primar…...

中国BI步入增长大周期,腾讯云ChatBI加速AI+BI融合
过去十年,大数据技术的快速发展,让数据消费前进一大步,数据价值得到一定程度的挖掘与释放,真正开启了“用数”的大时代。但数据分析繁杂的技术栈、复杂的处理过程以及程式化的交互方式,让“数据消费”的门槛始终降不下…...

揭秘Python:下划线的特殊用法,你绝对想不到!
在Python编程中,下划线(underscore)是一个常见而又强大的工具。它不仅仅是一个普通的字符,而是具有特殊含义和用法的符号。今天,我们就来揭开Python下划线的神秘面纱,探索它的各种妙用。 下划线的基本用法…...

深入探索Java世界中的Jackson魔法:玩转JsonNode
哈喽,大家好,我是木头左! 揭秘Jackson库:JSON处理的瑞士军刀 在Java的世界里,处理JSON数据就像是一场探险。幸运的是,Jackson库就像一把多功能的瑞士军刀,为提供了强大而灵活的工具来解析和操作…...

为什么要使用动态代理IP?
一、什么是动态代理IP? 动态代理IP是指利用代理服务器来转发网络请求,并通过不断更新IP地址来保护访问者的原始IP,从而达到匿名访问、保护隐私和提高访问安全性的目的。动态代理IP在多个领域中都有广泛的应用,能够帮助用户…...

【PB案例学习笔记】-09滚动条使用
写在前面 这是PB案例学习笔记系列文章的第8篇,该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码,小凡都上传到了gitee…...
C++中常见的构造函数类别
目录 摘要 默认构造函数(Default Constructor): 带参数的构造函数(Parameterized Constructor): 拷贝构造函数(Copy Constructor): 移动构造函数(Move C…...

万界星空科技MES系统功能介绍
制造执行系统或MES 是一个全面的动态软件系统,用于监视、跟踪、记录和控制从原材料到成品的制造过程。MES在企业资源规划(ERP) 和过程控制系统之间提供了一个功能层,为决策者提供了提高车间效率和优化生产所需的数据。 万界星空科技MES 系统基础功能&am…...
炸裂的开源AI语音生成模型ChatTTS
今天看到GitHub上开源了一个非常厉害的AI语音生成模型ChatTTS,可以生成和人类声音非常接近的语音,而且有语气、语调、可以停顿和发出笑声,再也没有了以前的AI味道 体验地址:https://colab.research.google.com/drive/1MYep5f0-BJ…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...