Spring之依赖注入(DI)和控制反转(IoC)——配置文件、纯注解
依赖注入
依赖注入(Dependency Injection,简称 DI)与控制反转(loC)的含义相同,只不过这两
个称呼是从两个角度描述的同一个概念。对于一个 Spring 初学者来说,这两种称呼很难理解,
下面我们将通过简单的语言来描述这两个概念。
当Java对象(调用者)需要调用另一个Java对象(被调用者 即被依赖对象)时,传统模式下 调用者会采用“new 被调用者”的方式来创建对象 这种方式会导致调用者和被调用者之间的耦合度增加

创建两个用户User1和User2 使User2依赖于User1
public class User1 {public void say(){System.out.println("User1说");}
}
public class User2 {private User1 user1;public void setUser1(User1 user1) {this.user1 = user1;}public void say(){user1.say();System.out.println("User2说");}
}
如果我们想使用User2的say()方法 需要先实例化User1对象 否则无法使用

正确应为

控制反转
在使用Spring框架后 对象的实例不再由调用者(User2)来进行创建 而是由Spring容器实现 Spring 容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移到了 Spring 容器,控制权发生了反转,这就是 Spring 的控制反转
从Spring的角度来看 Spring的容器负责将被依赖对象(User1)赋值给调用者(User2)的成员变量 这相当于为调用者注入了它的依赖实例 这就是Spring的依赖注入

基于xml配置文件的方式实现Bean管理和注入属性
属性setter方法注入
指 loC 容器使用 setter 方法注入被依赖的实例。通过调用无参构造器或无参静态工厂方法实例化 Bean后,调用该Bean 的 setter 方法,即可实现基于 setter 方法的依赖注入。
创建UserDao1和UserDao2
public interface UserDao1 {void say();
}
public interface UserDao2 {void say();
}
创建两个接口的实现类 并让User2的实现类依赖于User1
public class UserDao1Impl implements UserDao1 {@Overridepublic void say() {System.out.println("UserDao1说");}
}
public class UserDao2Impl implements UserDao2 {private UserDao1 userDao1;public void setUserDao1(UserDao1 userDao1) {this.userDao1 = userDao1;}public void say(){userDao1.say();System.out.println("UserDao2说");}
}
在applicationContext.xml中写入
<bean id="userDao1" class="com.qcby.spring.DaoImpl.UserDao1Impl"></bean><bean id="userDao2" class="com.qcby.spring.DaoImpl.UserDao2Impl"><property name="userDao1" ref="userDao1"></property>
</bean>
其中


测试类中
@Testpublic void UserDaoTest(){/*从类路径classpath 中寻找到xml文件 完成applicationContext实例*/ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");/*通过getBean获取配置文件中的信息 完成实例化*/UserDao2 userDao2 = (UserDao2) applicationContext.getBean("userDao2");userDao2.say();}
结果为

我们可以看到没有“new UserDao1”也实现了上述操作 实现了依赖注入
属性的set方法注入值
创建一个新的User对象
编写属性,提供该属性对应的set方法,编写配置文件完成属性值的注入
public class User {// 编写成员属性,一定需要提供该属性的set方法//IOC容器底层就通过属性的set方法方式注入值private int age;private String name;private Demo demo;public void setAge(int age) {this.age = age;}public void setName(String name) {this.name = name;}public void setDemo(Demo demo) {this.demo = demo;}@Overridepublic String toString() {return "User{" +"age=" + age +", name='" + name + '\'' +", demo=" + demo +'}';}
}
<!‐‐DI:依赖注入‐‐>
<bean id="user" class="com.qcby.service.User" ><!--使用property完成属性注入name:类里面属性名称value:向属性注入值ref:对象映射--><property name="age" value="18"></property><property name="name" value="张三"></property><property name="demo" ref="demo"></property>
</bean>
数组,集合(List,Set,Map)等的set注入
public class CollectionBean {private String [] strs;private List<String> list;private Map<String,String> map;public void setStrs(String[] strs) {this.strs = strs;}public void setList(List<String> list) {this.list = list;}public void setMap(Map<String, String> map) {this.map = map;}@Overridepublic String toString() {return "CollectionBean{" +"strs=" + Arrays.toString(strs) +", list=" + list +", map=" + map +'}';}
}
<!‐‐给集合属性注入值‐‐>
<bean id="collectionBean" class="com.qcby.service.CollectionBean"><property name="strs"><array><value>美美</value><value>小凤</value></array></property><property name="list"><list><value>熊大</value><value>熊二</value></list></property><property name="map"><map><entry key="aaa" value="老王"/><entry key="bbb" value="小王"/></map></property>
</bean>
通过构造方法注入
我们将UserDao2Impl中的setter方法进行删除 并添加上UserDao1的构造方法(构造方法是必不可少的)
public class UserDao2Impl implements UserDao2 {private UserDao1 userDao1;public UserDao2Impl(UserDao1 userDao1) {this.userDao1 = userDao1;}public void say(){userDao1.say();System.out.println("UserDao2说");}
}
在applicationContext.xml中写入 通过constructor-arg进行注入
<bean id="userDao1" class="com.qcby.spring.DaoImpl.UserDao1Impl"></bean><bean id="userDao2" class="com.qcby.spring.DaoImpl.UserDao2Impl"><constructor-arg ref="userDao1"></constructor-arg></bean>
测试类中结果为

在注入的同时进行赋值操作
对于类成员变量,构造函数注入
public class Car {// 名称private String cname;// 金额private Double money;public Car(String cname,Double money){this.cname = cname;this.money = money;}@Overridepublic String toString() {return "Car{" +"cname='" + cname + '\'' +", money=" + money +'}';}
}
<bean id="car" class="com.qcby.service.Car"><constructor-arg name="cname" value="奔驰"></constructor-arg><constructor-arg name="money" value="35"></constructor-arg>
</bean>
数组,集合(List,Set,Map)等的构造器注入
private String[] Strings;
private List<String> list;
private Map<String,String> map;public UserService( String[] Strings, List<String> list, Map<String, String> map) {this.Strings = Strings;this.list = list;this.map = map;
}
<bean id="user" class="com.qcby.service.UserService"><constructor-arg index="0"><array><value>aaa</value><value>bbb</value><value>ccc</value></array></constructor-arg><constructor-arg index="1"><list><value>小黑</value><value>小白</value></list></constructor-arg><constructor-arg index="2"><map><entry key="aaa" value="小黑"/><entry key="bbb" value="小号"/></map></constructor-arg>
</bean>
基于注解的方式实现Bean管理和注入属性
Spring针对Bean管理中创建对象提供的注解
- @Component 普通的类
- @Controller 表现层
- @Service 业务层
- @Repository 持久层
上边四个功能一样,都可以用来创建bean实例
在进行注解开发之前要现在配置文件中进行相关配置

编写对应的接口和实现类
public interface UserDao1 {void say();
}
@Controller(value="UserDao1")
public class UserDao1Impl implements UserDao1 {@Overridepublic void say() {System.out.println("UserDao1说");}
}
其中

用注解的方实现属性注入
- @Value 用于注入普通类型(String,int,double等类型)
- @Autowired 默认按类型进行自动装配(引用类型)
- @Qualifier 不能单独使用必须和@Autowired一起使用,强制使用名称注入
- @Resource Java提供的注解,也被支持。使用name属性,按名称注入
创建一个实体类Car
@Component(value = "c")
// @Controller
// @Service(value = "c")
// @Repository(valu = "c")
public class Car {// 注解注入值,属性set方法是可以省略不写的。// 只有一个属性,属性的名称是value,value是可以省略不写的@Value("大奔2")private String cname;@Value(value = "400000")private Double money;// 也不用提供set方法// 按类型自动装配的注解,和id名称没有关系@Autowired// 按id的名称注入,Qualifier不能单独使用,需要Autowired一起使用。// @Qualifier(value = "person")// @Resource Java提供的注解,按名称注入对象,属性名称是name// @Resource(name = "person")private Person person;@Overridepublic String toString() {return "Car{" +"cname='" + cname + '\'' +", money=" + money +", person=" + person +'}';}}
再在Car中的Person引用类进行注解注入
@Controller
//@Component(value = "person")
//此处没有对Person的使用 故可以不设置value值
public class Person {@Value("张三")private String pname;@Overridepublic String toString() {return "Person{" +"pname='" + pname + '\'' +'}';}}
在测试类中进行测试输出
@Testpublic void CarTest(){/*从类路径classpath 中寻找到xml文件 完成applicationContext实例*/ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");/*通过getBean获取配置文件中的信息 完成实例化*/Car car = (Car) applicationContext.getBean("car");System.out.println(car);}
![]()
IOC纯注解的方式代替配置文件
纯注解的方式是微服务架构开发的主要方式,所以也是非常的重要。纯注解的目的是替换掉所有的配置文件。但是需要编写配置类。
常用的注解总结
- @Configuration 声明是配置类
- @ComponentScan 扫描具体包结构的
编写实体类
@Component
public class Order {@Value("北京")private String address;@Overridepublic String toString() {return "Order{" +"address='" + address + '\'' +'}';}
}
编写配置类,替换掉applicationContext.xml配置文件
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcby")
public class SpringConfig {
}
测试方法的编写
package com.qcby.test;
import com.qcby.demo4.Order;
import com.qcby.demo4.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class Demo4 {@Testpublic void run(){// 创建工厂,加载配置类 // 此处new的对象和配置文件中不同ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);// 获取到对象Order order = (Order) ac.getBean("order");System.out.println(order);}
}
相关文章:
Spring之依赖注入(DI)和控制反转(IoC)——配置文件、纯注解
依赖注入 依赖注入(Dependency Injection,简称 DI)与控制反转(loC)的含义相同,只不过这两 个称呼是从两个角度描述的同一个概念。对于一个 Spring 初学者来说,这两种称呼很难理解, 下面我们将通过简单的语言来描述这两个概念。 当Java对象&…...
基于SpringBoot的宠物健康咨询系统的设计与实现
摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,宠物健康知识信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不…...
Lucene的使用方法与Luke工具(2)
文章目录 第2章 Lucene快速入门2.1 项目搭建2.1.1 SQL语句2.1.2 maven依赖2.1.3 实体类:2.1.4 编写DAO: 2.2 建立索引2.2.1 步骤:2.2.2 实现代码: 2.3 Luke工具2.3.1 运行界面介绍:1)主界面2)文…...
【客户端开发】electron 中无法使用 js-cookie 的问题
产生问题的原因 谷歌浏览器升级之后,出于安全考虑,cookie的SameSite属性默认值由None变为Lax,对于跨域的请求,禁止携带cookie。electron内核是chromium内核,所以也会有这个限制。 Cookie的SameSite属性用来限制第三方 Cookie&…...
kafka客户端消费者吞吐量优化
问题背景 业务场景 mq消息消费实时性要求不高,期望可以牺牲一部分实时性,换取吞吐量,例如:数据库单条insert优化为batchInsert。优化后结果不符合预期:消费者消费消息的batchSize远小于实际配置的max.poll.records&a…...
电子工程师-高质量工具包
目录 来源 高质量工具包介绍 总体框架如下 ZL01-各类元器件相关资料 ZL02-电源设计资料 ZL03-大厂参考资料 ZL04-开发工具 ZL05-仿真工具 ZL06-各类电路接口设计指南 ZL07-付费专栏全集 ZL08-优质电子书 ZL09-硬件工程师 ZL10FPGA工程师教程 ZL10-PCB设计教程 Z…...
简单认识redis - 12 redis锁
在斜体样式**redis中,不同的问题有不一样的解决办法,那么锁也有不同的锁来解决不一样的问题,下面将举出几个常用的redis锁。 1. SETNX锁(简单独占锁) 原理: SETNX(SET if Not eXistsÿ…...
基于springboot+vue车辆充电桩管理系统
基于springbootvue车辆充电桩管理系统 摘 要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,车辆充电桩管理系统也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,…...
shodan用法(完)
声明 学习视频来自B 站up主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 shodan 今天,我们把shoda…...
【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台
今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台,后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码,这就是若依的强大之处,即便你不会Java和vue开发,只要跟着石头哥也可…...
转子侧串级调速系统和双馈调速系统
转子侧串级调速系统和双馈调速系统是两种不同的电机调速技术,它们在基本原理、效率以及应用场景等方面存在区别。以下是详细的对比分析: 基本原理 转子侧串级调速系统:通过在绕线式异步电动机的转子回路中串入一个可调节的附加电势࿰…...
AI学习指南自然语言处理篇-Transformer模型的实践
AI学习指南自然语言处理篇 - Transformer模型的实践 目录 引言Transformer模型概述 自注意力机制编码器-解码器结构 环境准备Transformer模型的实现 编码器实现解码器实现Transformer模型整体实现 Transformer在NLP任务中的应用 文本分类机器翻译 总结与展望 引言 在过去的数…...
【LVGL速成】LVGL修改标签文本(GUI Guider生成的字库问题)
目录 前置篇章: 一.问题背景 二.失败方案 三.成功方案 1.Gui guider的源码结构 2.手动生成字体 3.Keil中配置相关文件 编辑 4.修改文字 四.字体样式函数说明 前置篇章: 【LVGL快速入门(二)】LVGL开源框架入门教程之框架使用(UI界面设计)_lvgl…...
C语言项目实践-贪吃蛇
⽬录: 1. 游戏背景 2. 游戏效果演⽰ 3. 实现的⽬标 4. 实现的定位 5. 技术要点 6. 贪吃蛇游戏设计与分析 7. 贪吃蛇游戏数据结构设计 8. 相关Win32API介绍 9. 参考代码 正文开始 1. 游戏背景 贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块…...
在kanzi 3.9.8里使用API创建自定义材质
1. kanzi studio设置 1.1 创建一个纹理贴图,起名Render Target Texture 1.2 创建一个Image节点,使用该贴图 2. 代码设置 2.1 创建一个自定义节点类 class mynode2d : public Node2D { public: virtual void renderOverride(Renderer3D& renderer…...
IDEA中通义灵码的使用技巧
大家好,我是 V 哥。在日常写代码的过程中,通过 AI 工具辅助开发已是当下程序员惯用的方式,V 哥在使用了众多的 AI 工具后,多数情况下,选择通义灵码来辅助开发,尤其是解释代码和生成单元测试功能甚是好用&am…...
JS中let var 和const区别
在JavaScript中,let、var 和 const 都是用来声明变量的关键字,但它们之间有几个关键的区别: 作用域(Scope): var 声明的变量拥有函数作用域(function scope),这意味着如果 var 变量在…...
ansible详细介绍和具体步骤
Ansible简介 1.1 Ansible的基本概念 Ansible是一款开源的自动化工具,旨在简化IT操作的复杂性。它由Michael DeHaan创建,并于2012年发布,随后在2015年被Red Hat收购。Ansible的核心理念是“简单即美”,它通过使用YAML(…...
利用LangChain与LLM打造个性化私有文档搜索系统
我们知道LLM(大语言模型)的底模是基于已经过期的公开数据训练出来的,对于新的知识或者私有化的数据LLM一般无法作答,此时LLM会出现“幻觉”。针对“幻觉”问题,一般的解决方案是采用RAG做检索增强。 但是我们不可能把…...
linux中的软、硬链接
目录 引言 简单介绍 如何理解软硬链接 链接的应用 环路问题 引言 在Linux操作系统的广阔天地中,文件管理是其核心功能之一。而软链接和硬链接作为Linux文件系统中的两种特殊链接方式,它们为用户提供了灵活的文件访问途径和高效的磁盘空间利用手段。…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
