详解Spring IoCDI(一)

目录

1.什么是IoC

2.IoC应用场景(案例分析) 

2.1传统程序开发

2.2问题分析

2.3解决方案

2.4IoC 优势

3. DI概念

4.IoC详解

4.1Bean的存储

 4.2@Controller(控制器存储)

4.3获取Bean

4.4Bean相关注解


1.什么是IoC

Spring是⼀个开源框架, 他让我们的开发更加简单、Spring 是包含了众多工具⽅法的 IoC 容器 、

IoC(Inversion of Control,控制反转)是Spring的核心思想,在传统的编程模式中,对象的创建和依赖关系的管理通常由程序自身来完成。而在使用了 IoC 思想的框架(如 Spring)中,这些对象的创建以及对象之间依赖关系的建立等控制权由框架来接管,而不是由应用程序代码直接控制

所谓的IOC称之为控制反转,简单来说就是将对象的创建的权力及对象生命周期的管理过程交由Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,而是在需要的时候由Spring框架提供,这个由Spring框架管理对象创建和生命周期的机制称之为控制反转。

2.IoC应用场景(案例分析) 

2.1传统程序开发

需求:造出一辆能跑的车

先设计轮⼦(Tire) ,然后根据轮⼦的⼤⼩设计底盘(Bottom) ,接着根据底盘设计⻋⾝(Framework) ,最后根据⻋⾝设计好整个汽⻋(Car)

这⾥就出现了⼀个"依赖"关系:汽车依赖车身,车身依赖底盘 ,底盘依赖轮⼦ .

 最终程序的实现代码如下:

public class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("car init...");}public void run() {System.out.println("car run...");}
}public class Framework {private Bottom bottom;public Framework() {bottom = new Bottom();System.out.println("framework init....");}
}public class Bottom {private Tire tire;public Bottom() {tire = new Tire();System.out.println("bottom init...");}
}public class Tire {public Tire() {System.out.println("tire init...size:"+size);}
}

2.2问题分析

这样的设计看起来没问题 ,但是可维护性却很低.接下来需求变更,我们需要加工多种尺寸的轮胎.

那这个时候就要对上⾯的程序进⾏修改了 ,修改后的代码如下所示:

修改之后, 其他调⽤程序也会报错, 们需要继续修改

 

从以上代码可以看出以上程序的问题是: 程序的耦合度⾮常⾼,当最底层代码改动之后 ,整个调用链上的所有代码都需要修改.

2.3解决方案

我们尝试换⼀种思路, 我们先设计汽车的⼤概样子 ,然后根据汽车的样子来设计车身,根据车身来设计 底盘 ,最后根据底盘来设计轮子 . 这时候 ,依赖关系就倒置过来了:轮⼦依赖底盘  底盘依赖车身,车身依赖汽车

此时 ,我们只需要将原来由⾃⼰创建的下级类 ,改为传递的⽅式(也就是注入的⽅式), 因为我们不需要在当前类中创建下级类了 ,所以下级类即使发⽣变化(创建或减少参数), 当前类本⾝也⽆需修改任何代码 ,这样就完成了程序的解耦. 

public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("car init...");}public void run(){System.out.println("car run...");}
}
public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;System.out.println("framework init....");}
}
public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;System.out.println("bottom init....");}
}
public class Tire {private int size;public Tire(int size) {this.size = size;this.color= color;System.out.println("tire init...size:"+size);}
}

代码经过以上调整 ,⽆论底层类如何变化 ,整个调⽤链是不⽤做任何改变的 ,这样就完成了代码之间的解耦 ,从而实现了更加灵活、通⽤的程序设计了。

2.4IoC 优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire

改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

通⽤程序的实现代码 ,类的创建顺序是反的 ,传统代码是 Car 控制并创建了Framework Framework 创建并创建了 Bottom ,依次往下 ,⽽改进之后的控制权发⽣的反转 ,不是使⽤⽅对象创建并控制依赖对象了是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制

这样的话, 即使依赖类发⽣任何改变  前类都是不受影响的 ,这就是典型的控制反转 ,也就是 IoC 实现思想。

IoC 的优点主要包括以下几点:

  1. 降低耦合度:使组件之间的依赖关系更加松散,便于系统的扩展和维护。
  2. 提高代码复用性:组件可以更方便地在不同场景中复用。
  3. 增强灵活性:可以更轻松地替换或修改依赖的对象,而不影响其他部分代码。
  4. 便于测试:可以方便地模拟和替换依赖对象,进行单元测试。
  5. 提升开发效率:开发者无需花费大量时间处理对象创建和依赖管理的繁琐细节。
  6. 更好的架构管理:有助于构建更清晰、合理的系统架构。

3. DI概念

IoC 是一种设计思想,而 DI(Dependency Injection,依赖注入)是实现 IoC 的一种重要方式。

DI 具体指的是将对象之间的依赖关系,通过一定的方式(如构造器注入、Setter 方法注入、字段注入等)在运行时动态地注入到对象中。

可以说 DI 是 IoC 思想在具体技术实现层面的体现,它们紧密相关,共同作用来实现对象创建和依赖管理的解耦与灵活配置。

创建Student类:

public class Student {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

创建一个Course类,并通过注解注入Student对象:

@Service
public class Course {@Autowiredprivate Student student;public void showDetails() {System.out.println("依赖注入学生姓名:" + student.getName());}
}

4.IoC详解

通过上⾯的案例, 我们已经知道了Spring IoC DI的基本操作, 接下来我们来系统的学习Spring IoCDI 的操作.前⾯我们提到IoC控制反转 ,就是将对象的控制权交给SpringIOC容器  IOC容器创建及管理对象。也就是bean的存储.

4.1Bean的存储

要把某个对象交给IOC容器管理 ,需要在类上添加⼀个注解:@Component

Spring框架为了更好的服务web应⽤程序, 提供了更丰富的注解.

共有两类注解类型可以实现:

类注解:@Controller@Service@Repository@Component@Configuration.

⽅法注解:@Bean. 

 4.2@Controller(控制器存储)

使用@Controller 存储 bean 的代码如下所示:

 @Controller // 将对象存储到 Spring 中public class UserController {public void sayHi(){System.out.println("hi,UserController...");}}

如何观察这个对象已经存在Spring容器当中了呢? 接下来我们学习如何从Spring容器中获取对象

 @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.sayHello();}
}
}

观察运⾏结果, 发现成功从Spring中获取到Controller对象, 并执⾏ControllersayHello⽅法

如果把@Controller删掉, 再观察运⾏结果

 报错信息显⽰: 找不到类型是: com.example.demo.controller.UserControllerbean

获取bean对象的其他⽅式:

上述代码是根据类型来查找对象, 如果Spring容器中, 同⼀个类型存在多个bean的话, 怎么获取呢

ApplicationContext 也提供了其他获取bean的⽅式, ApplicationContext 获取bean对象的功能, 是父BeanFactory提供的功能.

     // 1. 根据bean名称获取beanObject getBean(String var1) throws BeansException;// 2. 根据bean名称和类型获取bean<T> T getBean(String var1, Class<T> var2) throws BeansException;// 3. 按bean名称和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的beanObject getBean(String var1, Object... var2) throws BeansException;// 4. 根据类型获取bean<T> T getBean(Class<T> var1) throws BeansException;// 5. 按bean类型和构造函数参数动态创建bean,只适⽤于具有原型(prototype)作⽤域的bea<T> T getBean(Class<T> var1, Object... var2) throws BeansException;

常⽤的是上述1,2,4, 这三种⽅式,取到的bean是⼀样的,其中1,2种都涉及到根据名称来获取对象. bean的名称是什么呢?

Spring beanSpring框架在运⾏时管理的对象, Spring会给管理的对象起⼀个名字. ⽐如学校管理学⽣ , 会给每个学⽣分配⼀个学号, 根据学号, 就可以找到对应的学⽣ .

Spring也是如此, 给每个对象起⼀个名字, Bean的名称(BeanId)就可以获取到对应的对象.

4.3获取Bean

 @SpringBootApplicationpublic class SpringIocDemoApplication { public static void main(String[] args) { //获取Spring上下⽂对象ApplicationContext context = SpringApplication.run(SpringIocDemoApplication.class,args); //从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);System.out.println(userController1);System.out.println(userController2);System.out.println(userController3);

运⾏结果:

地址⼀样, 说明是同一个对象

继承关系和功能⽅⾯来说:

Spring 容器有两个顶级的接⼝ BeanFactory ApplicationContext。

其中 BeanFactory 提供了基础的访问容器的能力,

ApplicationContext 属于 BeanFactory 的⼦类 ,它除了继承了 BeanFactory 的所有功能之外, 它还拥有独特的特性 ,还添加了对国际化⽀持、资源访问⽀持、 以及事件传播等⽅⾯的⽀持

从性能⽅⾯来说:ApplicationContext ⼀次性加载并初始化所有的 Bean 对象 ,⽽ BeanFactory 是需要那个才去加载那个 ,因此更加轻量. (空间换时间)

4.4Bean相关注解

在 Spring 中,有一些与 Bean 相关的重要注解,比如:

@Component:这是一个通用的组件注解,用于将类标识为可被 Spring 容器管理的 Bean。

@Service:通常用于标识服务层的 Bean,业务逻辑层, 处理具体的业务逻辑.

@Repository:一般用于标识数据访问层(如数据库操作相关)的 Bean。

@Controller:控制层, 接收请求, 对请求进⾏处理, 并进⾏响应.

@Configuration :配置层. 处理项⽬中的⼀些配置信.

此外,还有@AutoWired用于自动注入依赖等注解,它们共同协作来实现对 Bean 的管理和配置

程序员看到类注解之后 ,就能直接了解当前类的用途.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/19003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

统计计算五|MCMC( Markov Chain Monte Carlo)

系列文章目录 统计计算一|非线性方程的求解 统计计算二|EM算法&#xff08;Expectation-Maximization Algorithm&#xff0c;期望最大化算法&#xff09; 统计计算三|Cases for EM 统计计算四|蒙特卡罗方法&#xff08;Monte Carlo Method&#xff09; 文章目录 系列文章目录一…

echarts性能优化

echarts数据量多的时候优化方案&#xff1a; 渲染的数据太多时&#xff0c;渲染的速度会变慢。 let data [];for (let i 0; i < 100000; i) {let style {};if (i % 2 0) {style.color "red";}data.push({value: i,itemStyle: style,}); } myEcharts init(c…

STM32-13-MPU

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 文章目录 STM32-12-MPU1. 内存保护单元MPU1. M…

交换机的三层交换技术

现有pc1与pc2不在同一个网段之下&#xff0c;通过交换机相连接。 进人交换机1&#xff0c;创建两个vlan 10和vlan 20 &#xff0c;进入串口2设置串口模式为access&#xff0c;并且设置默认vlan为10.进入串口3设置串口模式为access&#xff0c;并且设置默认vlan为20. 进入串口1…

深度解析搜索引擎广告(SEM)与社交媒体广告(SMM):NetFarmer助力企业数字化出海

在当今数字化时代&#xff0c;企业出海已经成为了一个必然趋势。然而&#xff0c;如何有效地在海外市场中推广品牌、吸引潜在客户&#xff0c;成为了众多企业面临的重要挑战。搜索引擎广告&#xff08;SEM&#xff09;和社交媒体广告&#xff08;SMM&#xff09;作为两种主要的…

如何下载b站(哔哩哔哩bilibili)的学习视频教程

方法1&#xff1a; 打开粘贴视频链接下载即可哔哩哔哩(bilibili)视频解析下载 - 保存B站视频到手机、电脑哔哩哔哩高清视频解析下载工具是一个免费的B站视频在线解析提取工具,支持提取B站APP和bilibili网站上的任何视频,提取出来的视频无水印.我们可以借助此下载器方便地将视频…

最大公约数和最小公倍数(函数)(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明函数&#xff1b; //最大公约数&#xff1b; int greatdivisor(int x, int y);//最小公倍数&#xff1b; int leastmultiple(int x, int y);int main() {/…

618精选编程书单:学好代码是用好大模型的基础

大家好&#xff0c;我是爱编程的喵喵。双985硕士毕业&#xff0c;现担任全栈工程师一职&#xff0c;热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…

如何选择适合自己需求的云服务器

最近明月接了一个跨境电商的代维业务&#xff0c;发现他们的云服务器很有代表性&#xff0c;今天就以此为例给大家分享一下应该如何选择适合自己需求的云服务器。像明月这样专做代维业务的可以说什么云服务器都体验过了&#xff0c;也发现大家在选择自己的云服务器的时候有很大…

加密资产私钥安全完整手册(一) ,bitget钱包为例

比特币和以太坊等加密货币的兴起开创了数字金融的新时代&#xff0c;但也带来了独特的安全挑战。这些代表现实世界价值的数字资产已成为黑客和窃贼的主要目标。为了安全地应对这种情况&#xff0c;了解私钥的基本概念至关重要。 私钥是加密货币所有权和安全性的基石。它们相当于…

VSCode小技巧,忽略不想格式化的代码行

零&#xff0e;格式化工具文档 1 . Black Ignoring sections功能 2 . autopep8 disabling-line-by-line功能&#xff1b;&#xff1b;–line-range选项 3 . Prettier prettier-ignore功能(例&#xff1a;适用于JS的// prettier-ignore&#xff0c;适用于CSS的/* prettier-igno…

HTML新春烟花盛宴

目录 写在前面 烟花盛宴 完整代码 修改文字

三步问题 | 动态规划

1.三步问题 题目连接&#xff1a;面试题 08.01. 三步问题 三步问题。有个小孩正在上楼梯&#xff0c;楼梯有n阶台阶&#xff0c;小孩一次可以上1阶、2阶或3阶。实现一种方法&#xff0c;计算小孩有多少种上楼梯的方式。结果可能很大&#xff0c;你需要对结果模1000000007。 2…

C语言 指针——指针变量的定义、初始化及解引用

目录 指针 内存如何编址&#xff1f; 如何对变量进行寻址&#xff1f; 用什么类型的变量来存放变量的地址? 如何显示变量的地址?​编辑 使用未初始化的指针会怎样&#xff1f; NULL是什么&#xff1f; 如何访问指针变量指向的存储单元中的数据&#xff1f; 指针变量的…

APP原生开发与框架开发的优劣势

电话管家APP商用也有几年时间了&#xff0c;但是客户一直都有遇到一些问题。 为什么我们的APP老是要升级&#xff1f; 为什么有些手机使用体验不好&#xff1f; 为什么有些公司的APP几天就开发出来上线了&#xff1f; 为什么有些公司的APP那么便宜&#xff1f; 今天就来从…

家政预约小程序08服务详情

目录 1 创建页面2 创建URL参数3 配置数据详情组件4 从分类页跳转到详情页5 搭建详情页总结 现在我们的小程序已经在首页和分类页展示了服务的列表信息&#xff0c;当用户点击具体的内容的时候需要打开详情页&#xff0c;本篇介绍一下详情页的开发。 1 创建页面 打开应用编辑器…

中学生学人工智能系列:如何用AI学英语

经常有读者朋友给公众号《人工智能怎么学》留言咨询如何使用人工智能学习语文、数学、英语等科目。这些都是中学教师、中学生朋友及其家长们普遍关注的问题。仅仅使用留言回复的方式&#xff0c;不可能对这些问题做出具体和透彻的解答&#xff0c;因此本公众号近期将推出中学生…

如何在phpMy管理对Joomla后台的登录密码进行重置

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;如何在phpMy管理对Joomla后台的登录密码进行重置&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希…

LeetCode题练习与总结:平衡二叉树--110

一、题目描述 给定一个二叉树&#xff0c;判断它是否是平衡二叉树。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,3,3,null,null,4,4] 输出&#xff1a;false示例 3&#xff1a…

【Java用法】java中计算两个时间差

java中计算两个时间差 不多说&#xff0c;直接上代码&#xff0c;可自行查看示例 package org.example.calc;import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit;public class MinusTest {public static void…