Spring系列三:IoC 与 DI
水晶帘动微风起,满架蔷薇一院香。
概述
在软件工程中,控制反转(IoC
)是一种设计思想,对象之间耦合在一起,在运行时自动绑定,并且它们编译时对所需要引用的对象是不确定的。在这个spring
教程中,通过示例了解ioc
和spring
中的依赖注入之间的区别。
什么是控制反转(IOC)
在传统面向对象设计的软件系统中,它的底层由N多个对象构成,各个对象之间通过相互合作。最终实现业务流程。控制反转意指把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活,尽管有些人认为使用服务定位器模式也可以提供控制反转。
使用控制反转作为设计准则有以下优点:
- 某个任务的执行与实现是分离的
- 每个模块更关注与自己的设计。
- 模块不需要关注其它系统,只需要依赖即可。
- 模块的升级不会影响其它模块
什么是依赖注入(DI)
IoC
是一种设计范例,其目标是对应用程序的各个组件提供更多控制,使这些组件可以完成工作。依赖注入是一种模式,用于创建对象依赖的对象实例,且在编译时期是无感知的。IoC
依赖于依赖注入,因为它需要一种机制来创建且引用需要的组件。
这两个概念以这种方式协同工作,允许编写更灵活、可重用和封装的代码。因此,它们是设计面向对象解决方案的重要概念。
如何实现IoC
在面向对象的编程中,有几种基本技术可以实现控制反转。如下:
- 使用工厂模式
- 使用服务定位器模式
- 使用以下任何给定类型的依赖项注入
- 构造函数注入
- setter注入
- 注解注入
Spring中的控制反转
org.springframework.beans
和org.springframework.context
包为Spring
框架的IoC
容器提供了基础功能。BeanFactory
接口提供了更高级的配置项,能够管理所有对象。ApplicationContext
接口建立在BeanFactory
之上(它是一个子接口),并添加了其他功能,例如与Spring
的AOP
功能的更轻松集成,消息资源处理(用于国际化),事件传播以及特定于应用程序层的上下文,例如作为Web
应用程序中使用的WebApplicationContext
BeanFactory
是Spring IoC
容器的主要实现,负责包含和管理上述Bean
。BeanFactory
接口是Spring
中的重要的IoC
容器接口。
BeanFactory
接口有许多实现。最常用的BeanFactory
实现是XmlBeanFactory
类。其他常用的类是XmlWebApplicationContext
。根据bean
的定义,工厂将返回所包含对象的不同实例(Prototype
设计模式),或者返回单个共享实例(Singleton
设计模式,其中实例是作用域中的单例)。的工厂)。将返回哪种类型的实例取决于bean
工厂的配置:获取bean
实例的API
是相同的。
在深入研究依赖注入类型之前,首先确定在spring
框架中创建bean
的方式,因为它将有助于理解下一部分的内容。
如何在Spring中创建bean实例
Bean
定义可以看作是创建一个或多个实际对象的配置。获取时,容器会查看命名bean
的配置,并使用该bean
定义封装的配置项来创建(或获取)实际对象。
使用构造函数
当使用构造函数方法创建bean
时,所有普通类都可以被Spring
使用并与之兼容。也就是说,正在创建的类不需要实现任何特定的接口或以特定的方式进行编码。仅指定bean
类就足够了。使用基于XML
的配置项时,可以像这样指定bean
类:
<bean id="exampleBean" class = "cn.howtodoinjava.ExampleBean"/>
使用静态工厂方法
在定义要使用静态工厂方法创建的bean
以及指定包含静态工厂方法的类的class
属性时,需要另一个名为factory-method
的属性来指定工厂方法本身的名称。
<bean id="exampleBean" class = "cn.howtodoinjava.ExampleBean" factory-method="createInstance"/>
Spring
希望能够调用此方法并返回一个可用的对象,得到对象之后,该对象将被视为是通过构造函数创建的。
使用实例工厂方法
以类似于通过静态工厂方法进行实例化的方式,使用实例工厂方法进行实例化是调用容器中现有bean
的factory
方法来创建新bean
。
<bean id="myFactoryBean" class="cn.howtodoinjava.MyFactoryBean">
<bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"></bean>
Spring的依赖注入
依赖项注入(DI
)背后的基本原则是,对象仅通过构造函数参数、工厂方法的参数或属性来定义它们的依赖项,这些参数是在对象实例被构造或从工厂方法返回后在对象实例上配置的。然后,容器的工作是在创建bean时实际注入这些依赖项。即由IoC
容器帮对象找相应的依赖对象并注入,而不是由对象主动去找,因此称为控制反转(IoC
)。
setter 注入
通过调用无参数构造函数或无参数静态工厂方法以实例化bean
之后,在bean
上调用setter
方法,可以实现基于setter
的DI
。
public class TestSetterDI {
DemoBean demoBean = null;
public void setDemoBean(DemoBean demoBean) {
this.demoBean = demoBean;
}
}
构造方法注入
基于构造函数的DI
是通过调用具有多个参数(每个参数代表一个对象实例)的构造函数来实现的。另外,调用带有特定参数的静态工厂方法来构造Bean
几乎是等效的,本文的其余部分将类似地考虑构造函数的参数和静态工厂方法的参数。
public class ConstructorDI {
DemoBean demoBean = null;
public TestSetterDI (DemoBean demoBean) {
this.demoBean = demoBean;
}
}
注解注入
注解注入只需要在需要在成员变量上添加@Autowire
注解即可
public class ConstructorDI {
@Autowire
private DemoBean demoBean;
}
}
spring面试题
组件和服务之间有什么区别?
组件是一组软件,这些组件将被其它应用程序所使用,且不会进行任何更改。所谓“不更改”是指使用应用程序不会更改组件的源代码,尽管它们可以通过组件作者允许的方式扩展组件来更改组件的行为。
服务与组件相似,供外部应用程序使用。主要的区别在于本地使用的组件(比如jar
文件、程序集、dll
或源导入)。服务将通过同步或异步的某个远程接口(例如,Web
服务,消息系统,RPC
或套接字)远程使用。
DI与服务定位器模式有何不同?
依赖项注入器的主要好处是,它允许根据环境和使用情况注入合适的服务实现。注入不是打破这种依赖性的唯一方法,另一种方法是使用服务定位器。服务定位器的基本思想是拥有一个对象,该对象知道如何掌握应用程序可能需要的所有服务。然后,它将扫描所有此类服务,并将它们存储为单例注册表中。当要求提供服务实现时,请求者可以使用令牌查询注册表并获取适当的实现。
通常,这些注册表是通过一些配置文件填充的。关键区别在于,使用服务定位器时,服务的每个用户都对定位器具有依赖性。定位器可以隐藏对其他实现的依赖关系,但是还是需要查看定位器。
使用哪个更好的服务(即服务定位器或依赖项注入)?
正如上文已经说过的,关键区别在于,使用服务定位器,服务的每个用户都对定位器有依赖性。这意味着必须在输入和输出方面了解服务定位器的详细信息。因此,实际上成为选择哪种模式的决定因素。
如果维护注册表信息既简单又必要,则可以使用服务定位器,或者直接使用依赖注入,因为它对服务的使用者是无感知的
构造函数注入或setter或注解注入哪个更好?
基于constructor
的注入,会固定依赖注入的顺序;该方式不允许我们创建bean
对象之间的循环依赖关系,这种限制其实是一种利用构造器来注入的益处 - 当你甚至没有注意到使用setter
注入的时候,Spring
能解决循环依赖的问题;
基于setter
的注入,只有当对象是需要被注入的时候它才会帮助我们注入依赖,而不是在初始化的时候就注入;另一方面如果你使用基于constructor
注入,CGLIB
不能创建一个代理,迫使你使用基于接口的代理或虚拟的无参数构造函数。
我的偏好是注解注入,这种方式看起来非常好,精短,可读性高,不需要多余的代码,也方便维护;
什么是BeanFactory ?
BeanFactory
就像一个工厂类,其中包含一系列bean
。BeanFactory
在其内部保存多个Bean
的Bean
定义,然后在客户要求时实例化Bean
。
BeanFactory
能够在实例化协作对象之间创建关联。这消除了bean
本身和bean
客户端的配置负担。BeanFactory
还参与bean
的生命周期,从而调用自定义初始化和销毁方法。
什么是ApplicationContext ?
Bean
工厂适合简单的应用程序,但是要利用Spring
框架的全部功能,您可能需要升级到Spring
更高级的容器即应用程序上下文。从表面上看,应用程序上下文与Bean
工厂相同,两者都加载Bean
定义,将Bean
绑定在一起并根据请求分配Bean
。但它也提供如下功能:
- 解决文本消息的方法,包括对国际化的支持。
- 加载文件资源的通用方法。
- 为
bean
注册监听器的事件。
ApplicationContext的常见的实现有哪些 ?
ApplicationContext
的三种常用实现是:
ClassPathXmlApplicationContext
:它从位于类路径中的XML
文件中加载上下文定义,并将上下文定义视为类路径资源。使用代码从应用程序的类路径中加载应用程序上下文。ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
FileSystemXmlApplicationContext
:它从文件系统中的XML
文件加载上下文定义。使用代码从文件系统中加载应用程序上下文。
ApplicationContext context = new FileSystemXmlApplicationContext("bean.xml");
XmlWebApplicationContext
:它从Web
应用程序中包含的XML文件中加载上下文定义。
BeanFactory或ApplicationContext最好使用哪个 ?
BeanFactory
基本上只是实例化和配置Bean
。ApplicationContext
也可以做到这一点,它提供了支持基础设施来支持许多企业特有的特性,例如事务和AOP
。
因此,建议使用ApplicationContext
。
在本教程中,我们在spring
学习了ioc
和di
之间的区别。
Spring系列三:IoC 与 DI的更多相关文章
- Spring系列(1)--IOC 和 DI
IOC 和 DI IOC 原理 xml 配置文件配置 bean dom4j 读取配置文件 工厂设计模式 反射机制创建对象 applicationContext.xml 配置文件,该配置文件名可自定义: ...
- Spring系列之IOC的原理及手动实现
目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 导语 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架.也是几乎所有J ...
- 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)
用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是 ...
- Spring核心思想——IOC和DI
基本概念 IOC是什么? IOC(Inversion of Control)控制反转,IOC是一种新的Java编程模式,目前很多轻量级容器都在广泛使用的模式. IOC解决了什么问题? ...
- 初识Spring框架实现IOC和DI(依赖注入)
学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的, IoC是 ...
- Spring自学教程-IOC、DI、AOP(二)
一.spring的IOC-就是怎样使用spring来创建对象 二.springDI(依赖注入)-就是怎样给属性赋值 通过set方式赋值 以下我们只需要记住两点的赋值,基本类型和引用类型的赋值 基本类型 ...
- Spring 简单使用IoC与DI——XML配置
目录 Spring简介 导入jar包 Spring配置文件 Spring的IoC IoC简介 快速使用IoC Spring创建对象的三种方式 使用构造方法 使用实例工厂 使用静态静态工厂 Spring ...
- 理解Spring中的IoC和DI
什么是IoC和DI IoC(Inversion of Control 控制反转):是一种面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度.其基本思想是:借助于"第三方" ...
- 学习Spring5必知必会(3)~Spring的核心 IoC 和 DI
一.Spring的核心 IoC(基于XML) 1.IoC容器 (1)BeanFactory容器创建对象: //使用BeanFactory @Test void testBeanFactory() th ...
随机推荐
- Flask-配置参数
Flask配置 Flask 是一个非常灵活且短小精干的web框架 , 那么灵活性从什么地方体现呢? 有一个神奇的东西叫 Flask配置 , 这个东西怎么用呢? 它能给我们带来怎么样的方便呢? 首先展示 ...
- Codeforces 601B. Lipshitz Sequence(单调栈)
Codeforces 601B. Lipshitz Sequence 题意:,q个询问,每次询问给出l,r,求a数组[l,r]中所有子区间的L值的和. 思路:首先要观察到,斜率最大值只会出现在相邻两点 ...
- 使用create-react-app创建项目(一)——端口配置
在package.json文件中找到 "scripts",在start中添加"set PORT=8000" "scripts": { &qu ...
- leetcode-hard-array-149. Max Points on a Line -NO
mycode 不会.... 参考 因为每次遍历一个点,也就是i的时候,都是新建的一个lines,所以也就是考虑了k相同b不同的情况 最后gcd函数就求最大公约数,来解决斜率精度的问题 class S ...
- vs下qt的信号与槽实现
实现主窗口中Add按钮的功能, 这一部分要特别注意,除了实现功能代码外,还需自己手动添加一些其他的代码(Qt Creator可以自动添加). 我们需要在2个地方添加代码. 第1个是在addressbo ...
- C++ STL——常用算法
目录 一 常用查找算法 二 常用遍历算法 注:原创不易,转载请务必注明原作者和出处,感谢支持! 注:内容来自某培训课程,不一定完全正确! 一 常用查找算法 /* find算法 查找元素 @param ...
- 怎么彻底关闭卸载删除Cortana小娜进程,最简单
原文地址:https://jingyan.baidu.com/article/90bc8fc8be67bcf653640cfa.html Win10中的Cortana是微软开发的一款个人AI助理,集聊 ...
- 在React中修改antd的样式
1.在Component的Radio中加个style={radioStyle}. <RadioGroup> <Radio style={radioStyle} value={}> ...
- React Native布局详解
Flexbox 布局 Flex有两个属性:Container 和 Item flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性.采用fle ...
- Mysql 查询当前数据上一条和下一条的记录
获取当前文件上一条与下一条记录的原理是上一条的sql语句,从news表里按从大到小的顺序选择一条比当前ID小的新闻,下一条的sql语句,从news表里按从小到大的顺序选择一条比当前ID大的新闻. 如果 ...