Spring系列三:IoC 与 DI

水晶帘动微风起,满架蔷薇一院香。java

https://user-gold-cdn.xitu.io/2019/10/18/16ddd77b37856c70?w=1920&h=1280&f=jpeg&s=338726
https://user-gold-cdn.xitu.io/2019/10/18/16ddd77b37856c70?w=1920&h=1280&f=jpeg&s=338726

概述

在软件工程中,控制反转(IoC)是一种设计思想,对象之间耦合在一块儿,在运行时自动绑定,而且它们编译时对所须要引用的对象是不肯定的。在这个spring教程中,经过示例了解iocspring中的依赖注入之间的区别。面试

什么是控制反转(IOC)

在传统面向对象设计的软件系统中,它的底层由N多个对象构成,各个对象之间经过相互合做。最终实现业务流程。控制反转意指把建立和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,因此对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得很是灵活,尽管有些人认为使用服务定位器模式也能够提供控制反转。spring

使用控制反转做为设计准则有如下优势:编程

  1. 某个任务的执行与实现是分离的
  2. 每一个模块更关注与本身的设计。
  3. 模块不须要关注其它系统,只须要依赖便可。
  4. 模块的升级不会影响其它模块

什么是依赖注入(DI)

IoC是一种设计范例,其目标是对应用程序的各个组件提供更多控制,使这些组件能够完成工做。依赖注入是一种模式,用于建立对象依赖的对象实例,且在编译时期是无感知的。IoC依赖于依赖注入,由于它须要一种机制来建立且引用须要的组件。设计模式

这两个概念以这种方式协同工做,容许编写更灵活、可重用和封装的代码。所以,它们是设计面向对象解决方案的重要概念。微信

如何实现IoC

在面向对象的编程中,有几种基本技术能够实现控制反转。以下:框架

  1. 使用工厂模式
  2. 使用服务定位器模式
  3. 使用如下任何给定类型的依赖项注入
  • 构造函数注入
  • setter注入
  • 注解注入

Spring中的控制反转

org.springframework.beansorg.springframework.context包为Spring框架的IoC容器提供了基础功能。BeanFactory接口提供了更高级的配置项,可以管理全部对象。ApplicationContext接口创建在BeanFactory之上(它是一个子接口),并添加了其余功能,例如与SpringAOP功能的更轻松集成,消息资源处理(用于国际化),事件传播以及特定于应用程序层的上下文,例如做为Web应用程序中使用的WebApplicationContext异步

BeanFactorySpring IoC容器的主要实现,负责包含和管理上述BeanBeanFactory接口是Spring中的重要的IoC容器接口。函数

https://user-gold-cdn.xitu.io/2019/10/18/16ddd7806eae992a?w=498&h=296&f=png&s=5950
https://user-gold-cdn.xitu.io/2019/10/18/16ddd7806eae992a?w=498&h=296&f=png&s=5950

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但愿可以调用此方法并返回一个可用的对象,获得对象以后,该对象将被视为是经过构造函数建立的。

使用实例工厂方法

以相似于经过静态工厂方法进行实例化的方式,使用实例工厂方法进行实例化是调用容器中现有beanfactory方法来建立新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方法,能够实现基于setterDI

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就像一个工厂类,其中包含一系列beanBeanFactory在其内部保存多个BeanBean定义,而后在客户要求时实例化Bean

BeanFactory可以在实例化协做对象之间建立关联。这消除了bean自己和bean客户端的配置负担。BeanFactory还参与bean的生命周期,从而调用自定义初始化和销毁​​方法。

什么是ApplicationContext ?

Bean工厂适合简单的应用程序,可是要利用Spring框架的所有功能,您可能须要升级到Spring更高级的容器即应用程序上下文。从表面上看,应用程序上下文与Bean工厂相同,二者都加载Bean定义,将Bean绑定在一块儿并根据请求分配Bean。但它也提供以下功能:

  • 解决文本消息的方法,包括对国际化的支持。
  • 加载文件资源的通用方法。
  • bean注册监听器的事件。

ApplicationContext的常见的实现有哪些 ?

ApplicationContext的三种经常使用实现是:

  1. ClassPathXmlApplicationContext:它从位于类路径中的XML文件中加载上下文定义,并将上下文定义视为类路径资源。使用代码从应用程序的类路径中加载应用程序上下文。
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    
    复制代码
  2. FileSystemXmlApplicationContext:它从文件系统中的XML文件加载上下文定义。使用代码从文件系统中加载应用程序上下文。
ApplicationContext context = new FileSystemXmlApplicationContext("bean.xml");
复制代码
  1. XmlWebApplicationContext:它从Web应用程序中包含的XML文件中加载上下文定义。

BeanFactory或ApplicationContext最好使用哪一个 ?

BeanFactory基本上只是实例化和配置BeanApplicationContext也能够作到这一点,它提供了支持基础设施来支持许多企业特有的特性,例如事务和AOP

所以,建议使用ApplicationContext

在本教程中,咱们在spring学习了iocdi之间的区别。


https://user-gold-cdn.xitu.io/2019/10/14/16dc81e2dd98c311?w=258&h=258&f=jpeg&s=26702
https://user-gold-cdn.xitu.io/2019/10/14/16dc81e2dd98c311?w=258&h=258&f=jpeg&s=26702

🙂🙂🙂关注微信公众号java干货 不按期分享干货资料

原文连接:Spring – IoC Containers

相关文章
相关标签/搜索