理解Spring中的依赖注入和控制反转
依赖注入(Dependency Injection)是一种面向对象编程的设计模式,用于解决对象之间的依赖关系。它的基本思想是将对象的创建和管理工作交给容器来完成,而不是在应用程序中手动创建和管理对象,从而达到松耦合、易维护、易测试的目的。依赖注入的实现原理是通过反射机制实现的。当一个对象需要依赖其他对象时,容器会通过反射机制查找和创建相应的对象,并将它们注入到需要依赖的对象中。这样,对象之间的依赖关系就由容器来维护,开发者只需要通过配置文件或注解等方式,告诉容器如何创建和注入对象。
在 Spring 框架中,依赖注入是通过 IoC(Inverse of Control,控制反转)实现的。IoC 容器在启动时,会扫描应用程序中的 Bean,并为每个 Bean 创建一个实例,并将它们存储在容器中。当其他 Bean 需要依赖这些 Bean 时,容器会自动将它们注入到需要依赖的 Bean 中。
具体来说,Spring 框架中的依赖注入主要有以下三种方式:
基于构造函数的依赖注入:通过构造函数来注入依赖项。
基于 Setter 方法的依赖注入:通过 Setter 方法来注入依赖项。
基于字段注入:通过直接将依赖项注入到类的字段中来实现。
那么什么是控制反转IoC呢?IoC 的基本思想是将程序中对象之间的依赖关系由程序员手动控制转变为由容器自动控制,即将对象的创建和管理工作交给容器来完成,而不是在应用程序中手动创建和管理对象。
依赖注入实际是通过反射机制实现的,反射机制实现依赖注入的具体步骤如下所示:
读取配置文件或者注解,获取依赖关系信息。
遍历依赖关系,通过反射机制获取依赖对象的类类型,然后使用 Class 类的 newInstance() 方法创建对象实例。
如果依赖对象有构造器参数,则通过递归调用实现构造器注入。
如果依赖对象有 setter 方法,则通过反射调用 setter 方法实现属性注入。
既然依赖注入本质是通过反射机制实现,那么什么是反射机制呢?反射机制是指在程序运行时动态获取类信息、访问或修改对象属性、调用对象方法等操作的一种机制。Java 反射机制提供了一组 API,使得程序能够在运行时获取并使用类的信息,而不需要在编译期间就确定。Java 反射机制提供了以下一些常用的 API:
Class 类:表示一个类的信息,可以获取类名、包名、父类、接口、构造器、属性、方法等信息。
Constructor 类:表示一个类的构造器信息,可以获取构造器的参数、修饰符、注解等信息。
Field 类:表示一个类的属性信息,可以获取属性名、类型、修饰符、注解等信息。
Method 类:表示一个类的方法信息,可以获取方法名、返回类型、参数、修饰符、注解等信息。
Modifier 类:提供了一组静态方法,可以判断一个类、方法或属性的修饰符,如 public、private、static、final 等。
Array 类:提供了一组静态方法,可以创建数组对象、获取数组长度、获取数组元素等信息。
下面是一段demo代码,通过实际代码来理解Java提供的反射机制的API如何使用。如下图所示,左边是定义的一个简单Person的class,右边是调用反射机制提供的API或者Person类的构造器,属性,对属性进行设置,调用Person类的方法等。在获取属性时,我们使用了 setAccessible(true) 方法,这是因为 name 和 age 属性都是私有的,需要通过反射机制打开访问权限才能修改它们的值。在调用方法时,我们使用了 invoke 方法来执行该方法。

可以看到通过反射机制,可以获取构造函数,设置属性值等,下面看看如何通过反射机制提供的API实现依赖注入。在下面的代码中,创建了UserService,UserService依赖UserDao。使用Class.forName()方法获取UserService类的Class对象,然后使用getConstructor()方法获取UserService类的构造函数,该构造函数需要一个UserDao类型的参数。接着,我们创建一个UserDao对象,然后通过newInstance()方法调用构造函数来创建UserService对象并注入依赖。另外,我们还可以使用getMethod()方法获取UserService类的setter方法,然后使用invoke()方法调用该方法来注入依赖。
public class UserService {private UserDao userDao;// 构造函数注入public UserService(UserDao userDao) {this.userDao = userDao;}// setter方法注入public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}
public class UserDao {// ...
}
public class Main {public static void main(String[] args) throws Exception {// 通过反射机制创建UserService对象并注入依赖Class<?> userServiceClass = Class.forName("com.example.UserService");Constructor<?> userServiceConstructor = userServiceClass.getConstructor(UserDao.class);UserDao userDao = new UserDao();UserService userService = (UserService) userServiceConstructor.newInstance(userDao);// 或者通过setter方法注入依赖Method setUserDaoMethod = userServiceClass.getMethod("setUserDao", UserDao.class);userDao = new UserDao();setUserDaoMethod.invoke(userService, userDao);}
}以上是Spring使用Java的反射机制实现依赖注入的简单介绍。当然,Spring中的依赖注入还涉及到很多细节和实现方式,但是基本的原理就是通过反射机制动态地创建对象并注入依赖。总结而言,Spring实现依赖注入可以划分为4个步骤:
配置Bean
在Spring中,Bean的配置可以通过XML配置文件、注解或Java代码来实现。在配置中可以定义Bean的属性、依赖关系等信息,这部分是程序员编写,例如通过注解@Autowired等进行配置。
容器创建Bean
当Spring容器(容器是Spring框架的核心,它负责创建、管理和调用Bean)启动时,它会根据配置文件中的定义,通过Java的反射机制创建所有需要的Bean,并将它们存储在容器中。
注入依赖
在容器创建Bean的过程中,Spring会通过依赖注入的方式自动将Bean所需要的依赖注入到Bean中。这个过程可以通过构造器注入、setter注入或接口注入来实现。
构造器注入:使用Bean的构造器来注入依赖。在Bean的构造器中,我们可以通过参数来传递依赖对象。Spring会通过Java的反射机制,自动为构造器注入需要的依赖对象。
setter注入:使用Bean的setter方法来注入依赖。在Bean中,我们可以定义setter方法来设置依赖对象。Spring会通过Java的反射机制,自动调用Bean的setter方法,将需要的依赖对象注入到Bean中。
接口注入:使用接口来注入依赖。在Bean中,我们可以定义一个接口,并在接口中定义依赖注入的方法。Spring会通过Java的反射机制,自动实现这个接口,并将实现后的对象注入到Bean中。
总的来说,Spring实现依赖注入的核心就是将Bean的创建和依赖注入的过程交给了Spring容器来管理。Spring容器在创建Bean的过程中,通过Java的反射机制来自动完成Bean的依赖注入。这种方式可以大大减少代码的复杂度,提高代码的可读性和可维护性。
相关文章:
理解Spring中的依赖注入和控制反转
依赖注入(Dependency Injection)是一种面向对象编程的设计模式,用于解决对象之间的依赖关系。它的基本思想是将对象的创建和管理工作交给容器来完成,而不是在应用程序中手动创建和管理对象,从而达到松耦合、易维护、易…...
XXL-JOB
XXL-JOB介绍 XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 官网:https://www.xuxueli.com/xxl-job/ 文档:分布式任务调度…...
「牛客网C」初学者入门训练BC134,BC136
🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️🔥专栏系列:线性代数,C初学者入门训练 🔥座右铭:“不要等到什么都没有了,才下定决心去做” 🚀🚀🚀大家觉不错…...
华为OD机试题【翻转单词顺序】用 C++ 进行编码 (2023.Q1)
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明翻转单…...
4.Spring【Java面试第三季】
4.Spring【Java面试第三季】前言推荐4.Spring27_Aop的题目说明要求Spring的AOP顺序AOP常用注解面试题28_spring4下的aop测试案例业务类新建一个切面类MyAspect并为切面类新增两个注解:spring4springboot1.5.9pom测试类29_spring4下的aop测试结果aop正常顺序异常顺序…...
ZLibrary使用说明-Zlirbrary
ZLibrary使用说明如果您是一位书虫,那么ZLibrary是一个值得一试的网站。该网站提供了大量的免费电子书籍,涵盖了各种不同的主题和类别。下面是一些有关如何使用ZLibrary的详细说明:第1步:访问ZLibrary网站要使用ZLibraryÿ…...
TwinCAT3第三方伺服电机——汇川SV660N使用
目录 一、第三方伺服在TC3中配置和使用 二、xml文件拷贝 编辑 三、IO中扫描伺服 四、工程测试 五、汇川伺服参数设置说明 一、第三方伺服在TC3中配置和使用 在倍福控制系统中使用第三方伺服可以参见本人另一篇博客,有详细教程说明。本文仅仅对SV660N伺服设置…...
进制转换(二进制,八进制,十进制,十六进制)涵盖整数与小数部分,内容的图片全为手写【详细图解】
各种进制之间的相互转换1. 各进制表示数1.1 数码1.2 基数1.3 位权2. 十进制转换为其他进制2.1 整数部分2.2 小数部分3. 其他进制转换为十进制4. 二进制转换为八进制5. 二进制转换为十六进制6. 八进制转换为十六进制1. 各进制表示数 二进制:0,1逢二进一 八…...
谈谈XR关键技术及VR/AR/MR/XR关系
一、先别被VR/AR/MR/XR搞晕,说说区别虚拟现实(Virtual Reality,VR)、增强现实(Augmented Reality,AR)等业务以其三维化、自然交互、空间计算等完全不同于当前移动互联网的特性,被认为…...
acwing1562 微博转发(宽搜)
微博被称为中文版的 Twitter。 微博上的用户既可能有很多关注者,也可能关注很多其他用户。 因此,形成了一种基于这些关注关系的社交网络。 当用户在微博上发布帖子时,他/她的所有关注者都可以查看并转发他/她的帖子,然后这些人…...
如何使用Arsenal快速部署功能强大的Bug Bounty工具
关于Arsenal Arsenal是一个功能强大且使用简单的Shell脚本(Bash),该工具专为漏洞赏金猎人设计,在该工具的帮助下,我们可以轻松在自己环境中安装并部署目前社区中功能最为强大的网络侦查工具、漏洞扫描工具和其他安全研…...
(十)python网络爬虫(理论+实战)——正则表达式再讨论、常用正则表达式整理
系列文章目录 (1)python网络爬虫—快速入门(理论+实战)(一) (2)python网络爬虫—快速入门(理论+实战)(二) (3) python网络爬虫—快速入门(理论+实战)(三) (4)python网络爬虫—快速入门(理论+实战)(四) (5)...
MyBatis-Plus特性及插件整合
了解MyBatis-Plus 什么是MyBatis-Plus? mybatisPlus在mybatis的基础上继续针对CRUD操作进行优化,在原有的基础上提供了公共的接口BaseMapper,我们在创建接口Mapper时只需要继承这个接口即可调用MyBatisPlus已经提供好的方法,sql…...
应用篇|网络安全知识培训考试,答题小程序操作指引
网络安全知识培训考试,答题小程序操作指引关于全民防诈反诈宣传或者网络安全知识学习,如何进行组织一场微信线上答题考试?可以在小程序“护网专题信息安全知识竞答”,先创建一个学习单位/小组,再邀请成员加入单位/小组…...
官方不推荐@Autowired
1用lombok注解 2 构造器...
【牛客刷题专栏】0x0E:JZ6 从尾到头打印链表(C语言编程题)
前言 个人推荐在牛客网刷题(点击可以跳转),它登陆后会保存刷题记录进度,重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏:个人CSDN牛客刷题专栏。 题目来自:牛客/题库 / 在线编程 / 剑指offer: 目录前言问题…...
Zeppelin安装
1、下载Zeppelin 下载地址:Download 2.解压 [rootguo147 install]# tar -zxvf zeppelin-0.10.0-bin-all.tgz -C ../soft/ //修改文件名 [rootguo147 soft]# mv zeppelin-0.10.0-bin-all/ zeppelin 3.配置 //进入conf 目录 [rootguo147 conf]# pwd /opt/soft/zepp…...
【蓝桥杯选拔赛真题38】python目标值判断 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析
目录 python目标值判断 一、题目要求 1、编程实现 2、输入输出 二、解题思路...
Python jieba分词如何添加自定义词和去除不需要长尾词
Python jieba分词如何添加自定义词和去除不需要长尾词 作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 通过如下代码,读取一个txt的高频词汇: # 找到高频词汇t…...
云打包苹果证书生成、上架和应用截屏攻略
在使用apicloud或hbuilderx这些跨端的开发工具开发移动应用的时候,假如是打包ios应用,是需要生成苹果证书、证书profile文件,和对应用上架的。首先要普及一个概念,苹果的应用是无法像安卓那样挂在自己的服务器上下载直接安装就可以…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
