文章

Ioc与di

IoC

IoC本身不是一种实现,而是一种思想。目的是:解耦

The Inversion-of-Control (IoC) pattern, is about providing any kind of callback, which “implements” and/or controls reaction, instead of acting ourselves directly (in other words, inversion and/or redirecting control to the external handler/controller). oop - What is Inversion of Control? - Stack Overflow

IoC(Inversion of Control)控制反转,包含了两个方面:⼀、控制。⼆、反转

我们可以简单认为:

控制指的是:当前对象对内部成员的控制权。

反转指的是:这种控制权不由当前对象管理了,由其他(类,第三⽅容器(在Spring中,通常是IoC容器)来管理。深入理解spring的两大特性 ioc 和aop-阿里云开发者社区 (aliyun.com)

案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class BookServiceImpl implements BookService{
    private Book book = new BookImp1();
    
	public void save(){
		book.save();
	}
}

public class BookImpl implements Book{
    public void save(){
        System.out.println("book 1 save ...")
    }
}

public class BookImp2 implements Book{
    public void save(){
        System.out.println("book 2 save ...")
    }
}

此时BookServiceImpl依赖于book对象。Book有两个实现。

如果现在想改book的类型,则需要将BookServiceImpl重写。耦合度高。

此时利用IoC思想,将对象对内部成员的控制权让渡给外部

1
2
3
4
5
6
7
public class BookServiceImpl implements BookService{
    private Book book;
    
	public void save(){
		book.save();
	}
}

此时还需要有人把BookServiceImplBook的某个对象绑定依赖。

IoC Service Provider

IoC Service Provider是一个抽象概念,不存在什么特定的物理实现。

虽然业务对象可以通过IoC方式声明相应的依赖,但是最终仍然需要通过某种角色或者服务将这些相互依赖的对象绑定到一起,而IoC Service Provider就对应IoC场景中的这一角色。

IoC Service Provider在这里是一个抽象出来的概念,它可以指代任何将IoC场景中的业务对象绑定到一起的实现方式。它可以是一段代码,也可以是一组相关的类,甚至可以是比较通用的IoC框架或者IoC容器实现。

IoC Service Provider 的职责:

  1. 对象的构建:在IoC场景中,业务对象无需关心所依赖的对象如何构建如何取得,但这部分工作始终需要有人来做,IoC Service Provider来干。

  2. 对象间的依赖绑定:对于IoC Service Provider来说,这个职责是最艰巨也是最重要的,这 是它的最终使命之所在。如果不能完成这个职责,那么,无论业务对象如何的“呼喊”,也不会得到依赖对象的任何响应(最常见的倒是会收到一个NullPointerException)。IoC Service Provider通过结合之前构建和管理的所有业务对象,以及各个业务对象间可以识别的依赖关系,将这些对象所依赖的对象注入绑定,从而保证每个业务对象在使用的时候,可以处于就绪状态。

    容器通过读取配置元数据来获得关于要实例化、配置和组装哪些对象的指示。配置元数据以XMLJava注解或Java代码表示。它可以让你表达构成你的应用程序的对象以及这些对象之间丰富的相互依赖关系。

IoC容器

IoC容器是一个IoC Service Provider

Spring提供了一个容器,称为IoC容器,用来充当Ioc思想中的外部 被创建或被管理的对象在Ioc容器中统称为Bean

image-20240229233415097

把对象放在IoC容器,需要了就从IoC容器中拿,不需要自己new了,此时这个对象被称为Bean。

如果service依赖于dao(Data Access Object)运行,且它们同时都在IoC容器中,IoC Service Provider会建立bean与bean之间的依赖关系,这被称为DI (Dependency Injection)

Spring的IoC容器是一个提供IoC支持的轻量级容器,除了基本的IoC支持,它作为轻量级容器还提供了IoC之外的支持。如在Spring的IoC容器之上,Spring还提供了相应的AOP框架支持、企业级服务集成等服务。Spring的IoC容器和IoC Service Provider所提供的服务 之间存在一定的交集。

image-20240301001800699

剩下的以后再来探索吧

DI

The Dependency-Injection (DI) pattern is a more specific version of IoC pattern, and is all about removing dependencies from your code.oop - What is Inversion of Control? - Stack Overflow

三种注入方式:

三种注入方式的比较

  1. 接口注入。从注入方式的使用上来说,接口注入是现在不甚提倡的一种方式,基本处于“退役状态”。因为它强制被注入对象实现不必要的接口,带有侵入性。而构造方法注入和setter 方法注入则不需要如此。

  2. 构造方法注入。这种注入方式的优点就是,对象在构造完成之后,即已进入就绪状态,可以 马上使用。缺点就是,当依赖对象比较多的时候,构造方法的参数列表会比较长。而通过反 射构造对象的时候,对相同类型的参数的处理会比较困难,维护和使用上也比较麻烦。而且 在Java中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能需要引入多 个构造方法,而参数数量的变动可能造成维护上的不便。

  3. setter方法注入。因为方法可以命名,所以setter方法注入在描述性上要比构造方法注入好一些。 另外,setter方法可以被继承,允许设置默认值,而且有良好的IDE支持。缺点当然就是对象无 法在构造完成后马上进入就绪状态。

综上所述,构造方法注入和setter方法注入因为其侵入性较弱,且易于理解和使用,所以是现在使用最多的注入方式;而接口注入因为侵入性较强,近年来已经不流行了。

——《Spring揭秘》

本文由作者按照 CC BY 4.0 进行授权