首页 > 其他分享 >Spring ioc&DI

Spring ioc&DI

时间:2024-09-26 20:50:14浏览次数:11  
标签:构造方法 DI Spring 获取 bean spring 注解 ioc 我们

(一)认识 IOC和DI

1.IOC

    认识IOC之前我们先来说一下spring是什么,我们说spring就是一个框架,可以让我们开发更加简单,他内部有很多集成好的一些类,所以我们用一句更简单的话来概括spring:Spring就是一个包含了众多工具方法的IOC容器

    那什么是IOC呢?简单来说他的核心就是控制反转,也就是说Spring就是一个控制反转的容器,那什么是控制反转呢?其实我们在之前的练习代码中,我们也无形的使用过

    我们之前的代码我们会发现跟之前写的不一样了,我们明明没有实例化这个类,却能正确访问到,这就是因为我们使用了@RestController这个注解,这个注解会把对象交给Spring管理,Spring框架启动的时候会自动加载类然后把这个对象交给Spring管理,这就是我们说的控制反转

   那我们spring就是一个ioc容器,而且通过ioc的思想,spring就有以下的优点:

1)资源集中管理:ioc容器会帮我们管理一些对象,我们使用的时候,只需要从ioc容器中获取

2)我们在创建实例的时候,降低了耦合度,交由spring来帮我们创建

2.DI

   那什么是DI呢?也叫做依赖注入,容器在运行的期间,动态的为我们的程序提供运行时所需要依赖的资源,就是依赖注入,通过控制反转和依赖注入,我们就可以实现对象之间的解耦

(二)IOC和DI的使用

   我们说spring是一个ioc容器,那就必须要具备存取的功能,我们也说ioc思想就是把类或者方法来交给spring管理,我称他为存,那di就是依赖注入,拿到我们想要的东西,我称为取。

  我们主要交给spring管理的是对象,这些对象又叫做“bean”,那我们spring创建及管理对象,也就是bean的存储了。

  1.Bean的存储

   如果我们向把某个对象交给IOC容器进行管理需要在类上添加一个注解@Component,spring框架给我们提供了更多不同的注解

   共有两大类注解可以实现我们的控制反转:

   1)类注解:@Controller、@Service、@Repository、@Component、@Configuration.

   2)方法注解:@Bean

   我们可以发现这个类注解的名称,跟我们的三层架构有点像,那我们在代码中,不同层的架构就可以使用不同的类注解,更方便我们进行区分

      1)@Controller(控制器存储)

五大注解的使用大同小异,我们这里只举其中几个例子

   我们先来使用@Controller存储bean

这样我们就把这个对象交给spring来进行管理

观察Bean

  那我们怎么观察到spring中的对象?

我们先来看启动类

   我们看方法名称,ConfigurableApplicationContext:我们翻译一下就是Spring的上下文,因为我们的对象交给了Spring来帮我们管理,那在spring中想找到我们的对象,就需要知道他的上下文(就类似于我们英语的完形填空,如果我们要选出这个单词,我们要结合他的上下文)

   那为什么这个类可以获取到我们spring管理的bean呢?我们点进这个类来看一看

   他继承了一个ListableBeanFactory的这个类,我们是要获取到bean,那我们就再点进这个类中的看一看

我们在这里寻找,发现并没有获取bean的方法(getbean),所以我们再点进他的父类

这时我们要的结果出现了,这里有很多的getBean方法,光看名字就知道,是用来获取我们存放在spring中的bean的,那这些方法又有不同的参数,接下来我们就来说一下,这些参数是什么?

   看这个参数,需要我们来传一个名称,也就是Bean的名称,根据名称来获取到Bean,所以我们要求Bean的名称必须在Spring中是唯一的,如果不唯一,我们在获取的时候就会出错,不知道应该获取哪一个,并且需要我们是小驼峰的方式表示,特殊情况下,如果类名的前两位都是大写,那么bean的名称就是类的本身

   那如果我们不适用规范的名称会有什么问题?

    我们会发现给我们报错了,翻译过来就是没有bean的名称叫MyController,那这时我们又会有疑惑?我的名称跟类名称完全一致啊,那是因为spring在存储时,进行了改变,然后存储的

   那我们在来看他的内部Introspector这个类的内部就有我们的转化方式

他会先判断我们输入的名字是不是空,如果不为空,判断我们前两个字符是不是大写的,如果是就直接返回,如果不是,他就会把我们的名称转为首字母小写的驼峰来表示

    接下来我们看第二个获取bean的方式,通过传类型的方式

   这种方式需要我们把想要获取的bean的类型传入(个人觉得这种比较简单,不需要特别注意格式)

接下来我们看第三个获取bean的方式,通过传名字和类型的方式

这个方法就是上述两个的和,也可以获取到

一些常见的问题

    除了上述我们说名称有问题外,我们如果忘记添加五大注解,就会导致出现

   告诉我们没有找到这个Bean

   还有一个常见的问题就是我们在使用方法注解的时候,会出现如果我们使用类名来获取,就可能会导致内部有很多方法注解,我们不知道获取哪一个,我们会在后面说到Bean的时候来举例子

Spring中的单例模式

   这里我们会有疑问,那我们获取了三次bean,这三次获取到的,是同一个吗,那我们打印出来看看

   我们发现,确实是同一个,我们在多线程的时候,说到了单例模式,那这个的内部就是使用了单例模式,而且是单例模式中的饿汉模式,因为现在我们都是追求速度,懒汉模式能够给我们节省内存,但是大多数情况下,内存还是够用的,所以这里是用饿汉来实现的单例模式

常见面试题:

AppilcationContext和BeanFactory的区别:

   首先我们刚刚看源码知道,ApplicationContext是BeanFactory的子类,这就说明,ApplicationContext的功能比BeanFactory的功能要多,除此之外,ApplicatioinContext还添加了队国际化的支持,资源访问的支持,和事件传播等方面的支持。

   从性能方面来讲,ApplicationContext是一次性加载并且初始化所有Bean的对象,但是BeanFactory是需要才去加载就有点类似单例模式中饿汉和懒汉的实现

2)@Service(服务存储)

类似于Controller

甚至于我们的使用方式都一样

为什么要有五大注解

   我们省略了Repository,Configuration,Component这三个注解,因为这三个注解无论是使用方式,还是作用都和Service一样,那我们为什么还要弄出这么多个注解?

   我们来一一点进源码看一眼

   我们会发现有四个注解内部都使用了@component,其实这四个就是@component的衍生类,分成这么多个就是为了符合我们之前说的应用分层,如果你在Service层那我们最好就使用@Service,而且这么多注解,如果我们规范使用也可以使我们代码更加规整,一眼就可以看出这个是哪一个层的

   但是如果我们就是想混用,那也不是不可以,毕竟他们的功能都是类似的,但是有一个例外,那就是Controller,如果我们设计到了前端的映射,那我们就必须使用Controller或者包含Controller的注解,比如RestController

3)@Bean方法注解

定义一个对象

我们上面说了五大类注解,但是类注解存在两个问题:

1.如果我们使用外部包中的类,没办法添加类注解

2.一个类,如果需要多个对象,那就需要用到我们的方法注解

我们先来看如何去使用

   我们会发现报错了,找不到这个类型的bean,这是因为spring根本没有去看我们加载了@Bean注解的这个类,因为我们进程中有很多的类,有内部的有外部的,Spring不可能把所有的都加载一遍,所以他只会把添加了五大注解的类,存储到spring容器中

定义多个对象

我们发现为什么我这次使用了类注解,也报错了啊

这时我们看报错信息,他说我们找到了bean但是找到了三个

那这时,我们就不可以只通过类来获取bean我们需要告诉spring我们要获取的具体是哪一个bean

我们传入我们具体的一个方法名,这样就不会报错了

扫描路径

   我们刚刚出现了使用@Bean但没使用五大注解,会导致我们spring扫描不到,无法添加到spring容器中,所以被spring扫描到就至关重要,那我们是怎样去扫描的呢?

首先我们来更改下启动类的目录地址

我们把启动类放到了Controller里,我们发现找不到我们的bean了

我们默认扫描的其范围是Springboot启动类所在的包及其子包

   我们上述改变了启动类的位置,就导致我们找不到我们之前添加的注解了,自然也就放不到spring中,但是我们可以通过@ComponentScan这个注解来手动指定我们扫描的范围@ComponentScan 注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解 @SpringBootApplication 中了

2.依赖注入

   我们上面说完了ioc的一些细节,那这里我们就来学习下依赖注入也就是DI的细节,我们发现上述ioc的这些操作我们写代码一般不会手动用到因为都是spring帮我们管理好的,但是DI可我们写代码息息相关

   简单来说,DI就是把IOC容器中的对象取出来放到某个类的属性中,这其中最重要的注解就是@Autowired

依赖注入三种方式:

1.属性注入          2.构造方法注入           3.Setter注入

接下来我们会用这三种模式,实现把Service注入到Controller这个类的操作

1)属性注入:

属性注入是直接适用@Autowired注解来实现的,将Service注入到Controller中

如果我们注入成功了,那么在我们打印完Mycontroller后会执行service的方法

那我们发现,确实如我们所料

那我们再来试一下,如果我们把这个注解去掉了,我们是否还能获取到这个bean

    我们发现获取失败了,他说我们不可以使用这个类的方法,因为我们的service是空的,也就是说我们并没有创建这个实例,那我们就有疑问了,spring不是帮我们管理了一个吗,确实是这样的,但是需要我们手动去添加注解告诉spring,我们要获取这个bean

2)构造方法注入:

    我们都知道构造方法可以在这个对象创建的时候,替我们做一些初始化的操作,那我们就可以在这个阶段在构造方法的参数里,传一个由spring帮我们管理的bean

   我们发现我们确实能获取到我们的bean,但是,我们构造函数有一个规范,那就是如果添加了构造函数,就需要把无参的构造函数给显示添加,那我们添加一下无参构造函数看看

   我们发现报错了,他又说这个service是空的,也就是说我们这次依然没有获取到bean,这是因为什么呢?

   我们只有一个构造函数的情况下,是不需要加@Autowired的,但是如果有多个构造函数,需要指定默认构造函数,如果我们没有指定,就会默认使用无参的构造函数,所以我们切记,使用构造方法进行依赖注入,需要我们使用@Autowired注解,即使我们没有实现无参构造,也最好协商

那如果我们给两个构造函数都添加@Autowired会发生什么?

   我们看这个错误日志,他说错误的创建这个叫myController的这个bean,因为我们有两个@Autowired修饰的构造方法,也就是说,我们一个类的构造方法中,只可以有一个构造方法被@Autowired来修饰

3)Setter注入:

其实Setter注入和构造方法我个人觉得很类似,只是方法名称换成了set~

我们来看使用:

   会发现确实和构造方法类似哈,但是我们要知道构造方法是创建这个类,一定要执行的方法,但是set可不是啊,那我们使用构造方法注入时,是一定会找到这个bean然后给我们的构造方法使用,但是set方法又不一定执行到,所以我们把这个注解去掉试试

   我们发现,确实是没有拿到这个service的,也就是说,使用set方法注入,是一定要我们手动添加注解的不然我们spring还是挺懒的,不会给我们默认执行这个set方法

三种方法的优缺点(面试题)

@Autowired的问题

当同一个类型存在多个bean时,就会出现问题

这里的报错日志说,我们再找这个bean的时候,找到了三个,我们再看他给出的建议

我们可以使用@Primary,或者@Qualifier来解决这个问题

   首先就是@Primary,这个就是要我们来指定一个默认的bean,如果同时有多个bean,我就执行这一个

使用@Qualifier就是指定当前要注入的对象,也就是指定注入的bean

同时除了这个两种,我们jdk内也有一个注解可以实现这个功能@Resource

常见面试题:

@Autowired和@Resource的区别

1.@Autowired时spring框架提供,@Resource时jdk提供

2.@Autowired是通过类型注入,如果这个类型内有很多bean交给spring管理,就会出错,但是@Resource是支持更多参数设置的,比如我们可以通过名称来获取Bean

标签:构造方法,DI,Spring,获取,bean,spring,注解,ioc,我们
From: https://blog.csdn.net/huapiaoy/article/details/142531371

相关文章

  • 如何打造Java SpringBoot民宿山庄农家乐系统?2025最新毕业设计攻略
    ✍✍计算机毕业编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 如何打造流浪天使乐园管理系统?Java SpringBoot+Vue技术解析
    ✍✍计算机毕业编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • Using DISM to Check and Repair Windows Image
    Youcanusethe SFC (SystemFileChecker)and DISM (DeploymentImageServicingandManagement)commandstocheckandrepairtheintegrityofsystemfilesandComponentStoreofyourWindows(WindowsServer)image.Thesetoolscanbeextremelyusefulifyo......
  • 基于springboot的点餐系统的设计与实现(附源码、lw、ppt)
    博主介绍:✌十余年IT大项目实战经验、在某机构培训学员上千名、专注于本行业领域✌技术范围:Java实战项目、Python实战项目、微信小程序/安卓实战项目、爬虫+大数据实战项目、Nodejs实战项目、PHP实战项目、.NET实战项目、Golang实战项目。主要内容:系统功能设计、开题报告......
  • Spring
     1.简介spring是一种用于简化复杂的企业开发的轻量级框架(从目的来说),是一种轻量级IOC(控制反转)和AOP(面向切面)的容器框架spring官网Spring|Homespring官方中文文档官网https://www.docs4dev.com/docs/zh/spring-framework/软件开发原则ocp开闭原则  在软件开发过......
  • BeanFactery实现IOC,DI思想
    一.三种思想(Ioc,DI,AOP)Iocinversionofcontrol,控制反转,强调的是原来在程序中创建bean的权利反转给第三方。DIdepencyinjection,依赖注入,强调的是bean之间的关系,由第三方负责设置。AOPaspectorientedprogramming,面向切面编程,功能的横向抽取,主要的实现方式就是Proxy。......
  • C# Linq.FirstOrDefault、Linq.Where、Linq.AsParallel、List.Exists、List.Find、Dic
    C#Linq.FirstOrDefault、Linq.Where、Linq.AsParallel、List.Exists、List.Find、Dictionar.TryGetValue、HashSet.Contains性能的比较 今天我们来比较一下集合检索方法性能更优问题,测试代码publicclassEntity{publicintId{get;set;}publicintNo{......
  • codeforces round 971(div4)E(二分答案,禁用数学方法)
    解题历程:开始想的是用数学公式的方法,利用公式推出二次函数,再求出根,再用根求出答案,检查了一个小时,结果怎么改都有细微的偏差,最后发现答案先单调递减在单调递增,那么可以用二分答案的方法查找最小的答案,二分对细节的处理要求比较高,于是在二分中加入了一个限制,当二分的区间小于5时,就......
  • 交替方向乘子法(Alternating Direction Method of Multipliers,简称ADMM)
    ADMMADMM简介交替方向乘子法(AlternatingDirectionMethodofMultipliers)通常用于解决存在两个优化变量的只含等式约束的优化类问题,其一般形式为:min⁡......
  • linux 操作系统下dig命令的使用和介绍
    linux操作系统下dig命令的使用和介绍dig(DomainInformationGroper)是一个强大的命令行工具,用于查询DNS(域名系统)服务器,获取有关域名及其相关记录的信息。它广泛用于网络管理和故障排除dig命令的基本功能查询DNS信息:dig可以查询各种类型的DNS记录,包括A记录(IP地址)、MX记......