前言

这是因特奈特上面不知道第几万篇讲依赖注入(Dependency Injection)的文章,但是说明白的却寥寥无几,这篇文章尝试控制字数同时不做大多数。

首先,依赖注入的是一件很简单的事情。

为什么需要依赖注入

然后,假设我们有一个汽车Car,一个引擎接口Engine,两个引擎具体实现Level4Engine,Level5Engine。汽车可以长这样:

public class Car{
private Engine e;
public Car(){
e = new Level4Engine();
}
public void ignite(){
System.out.println()
}
}

现在要让汽车点火,简单:

public static void main(String[] args) {
Car c = new Car();
c.ignite();
}

但是假如我们想要换一个更高级的引擎,我们不得不修改Car的构造函数:

~~ e = new Level4Engine(); ~~

e = new Level5Engine();

然后重新编译。这就是代码的耦合,一方面假如需求不会经常改变,这个汽车只会使用Level4Engine,那没问题,这个代码很完美。但另一方面,假如引擎有多个,需求会经常改变,我们发现Level4Engine还不行,需要更高级的,而且新引擎还需要进行一系列复杂配置,那这个耦合就是灾难了。只是装配汽车的血汗工人,懂不了那么多的。

怎么进行依赖注入

依赖注入就是为了解决上述问题而生的。用依赖注入的写法解决上面的问题:

public class Car{
private Engine e;
public Car(Engine e){
this.e = e;
}
public void ignite(){
System.out.println()
}
} // 也可以使用xml进行配置
@Confignuration
public CarFactory{
@Bean
public Engine engine(){
var e = new Level5Engine();
e.complexConfig();
return e;
}
@Bean
public Car car(Engine e){
return new Car(e);
}
}

这里Car对Engine的依赖被抽了出去。Car不负责创建Engine,也不负责/无能力配置Enging。那么Engine抽出到了哪?又由谁注入给Car?总不能让Car对着一个壳子(Engine接口)点火吧。

答案当然是spring。spring把它们抽象为Bean,每个@Bean都通知spring

嘿我要给你一个新的bean,以后就交给你来管理了。

DI的优势

这样既解决了上述"汽车装配工需要引擎配置知识"的问题,也解决了"更改引擎非常困难"的问题:

  • 引擎制造者只关注如何制造出引擎,当现在生产条件不成熟就提供Level4Engine,反之就提供Level5Engine,可以随时更改并对其进行配置
  • 汽车装配工只关注装配工作,而不需要配置引擎。
  • 每次引擎更改后只需要对这个配置类进行编译,如果使用xml连编译也不需要了。

这真的就是依赖注入的全部内容了,不过围绕依赖注入相关还有很多话题可以讨论,下面扩展就是两个。

扩展1:使用自动装配代替手动装配

演示了在CarFactory中手动car,还没完,spring还能更聪明一些,它可以通过自动装配完成这个配置工作:

@Component
public class Car{
private Engine e; @Autowired
public Car(Engine e){
this.e = e;
} public void ignite(){
System.out.println()
}
} @Component
public class Level5Engine{
public void complexConfig(){
System.out.println("really complex stuff...");
}
} @Confignuration
@ComponentScan
public class CarFactory{}

CarFactory@ComponentScan告诉spring扫描当前类所在包下面的所有类,如果找到@Component注解就加入spring bean容器。这里明显Car和Level5Engine加入了容器(默认会类名首字母小写,所以加入的是carlevel5Engine)。然后@Autowired在当前容器中查找,如果找到需要注入的类型就自动注入:

	@Autowired
public Car(Engine e){
this.e = e;
}

Car的装配需要一个引擎,spring容器刚好有一个实现了Engine的Level5Engine引擎,所以这里自动注入。

扩展2: NoUniqueBeanDefinitionException自动装配歧义

最后一个不常见的问题,假如我们把两个引擎都标注了@Component会怎么样:

@Component
public class Level5Engine{
}
@Component
public class Level4Engine{
}

spring不知道用哪一个注入给car,所以抛出NoUniqueBeanDefinitionException,表示有多个候选注入对象,需要我们手动缩小范围(@Qualifier,@Component value,@Primary),关于这部分内容可以参见其他文章。

简明依赖注入(Dependency Injection)的更多相关文章

  1. 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)

    控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...

  2. 14.AutoMapper 之依赖注入(Dependency Injection)

    https://www.jianshu.com/p/f66447282780   依赖注入(Dependency Injection) AutoMapper支持使用静态服务定位构建自定义值解析器和自定 ...

  3. 依赖注入 | Dependency Injection

    原文链接: Angular Dependency Injection翻译人员: 铁锚翻译时间: 2014年02月10日说明: 译者认为,本文中所有名词性的"依赖" 都可以理解为 & ...

  4. Spring点滴七:Spring中依赖注入(Dependency Injection:DI)

    Spring机制中主要有两种依赖注入:Constructor-based Dependency Injection(基于构造方法依赖注入) 和 Setter-based Dependency Inje ...

  5. 设计模式之————依赖注入(Dependency Injection)与控制反转(Inversion of Controller)

    参考链接: 依赖注入(DI) or 控制反转(IoC) laravel 学习笔记 —— 神奇的服务容器 PHP 依赖注入,从此不再考虑加载顺序 名词解释 IoC(Inversion of Contro ...

  6. 理解依赖注入(Dependency Injection)

    理解依赖注入 Yii2.0 使用了依赖注入的思想.正是使用这种模式,使得Yii2异常灵活和强大.千万不要以为这是很玄乎的东西,看完下面的两个例子就懂了. class SessionStorage { ...

  7. AngularJS - 依赖注入(Dependency Injection)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ 依赖注入 依赖注入是软件设计模式中的一部分,用于处理组件是如何得到它说依赖的其它组件的. ...

  8. Spring之对象依赖关系(依赖注入Dependency Injection)

    承接上篇: Spring中,如何给对象的属性赋值: 1:通过构造函数,如下所示: <!-- 1:构造函数赋初始值 --><bean id="user1" clas ...

  9. MVC使用StructureMap实现依赖注入Dependency Injection

    使用StructureMap也可以实现在MVC中的依赖注入,为此,我们不仅要使用StructureMap注册各种接口及其实现,还需要自定义控制器工厂,借助StructureMap来生成controll ...

随机推荐

  1. copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)

    写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...

  2. UML建模之类图

    UML类间关系的种类 从一个示例开始 请看以下这个类图,类之间的关系是我们需要关注的: 车的类图结构为<<abstract>>,表示车是一个抽象类: 它有两个继承类:小汽车和自 ...

  3. Spring思维导图(AOP篇)

    什么是aop AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP允许 ...

  4. Auth模块

    文本目录 1 扩展默认的auth_user表 2 auth模块是什么 3 auth模块的常用方法 1 扩展默认的auth_user 表 在开始写项目之前,我们要创建表,同事内置的认证系统又很好用,但是 ...

  5. cenots7单机安装Kubernetes

    关于什么是Kubernetes请看另一篇内容:http://www.cnblogs.com/boshen-hzb/p/6482734.html 一.环境搭建 master安装的组件有: docker ...

  6. 解决gitosis中authorized_keys不自动更新问题

    1.拷贝一个管理员权限用户的id_rsa.pub到服务器端 这里我拷贝的是yang电脑的key,命令如下: scp  /home/yang/.ssh/id_rsa.pub serveradmin@服务 ...

  7. spring mvc 入门程序

    入门程序 1.环境准备 myeclipse Spring jar 2.前端控制器设置 (web.xml) 所有的*.action请求通过org.springframework.web.servlet. ...

  8. 字节序(Endian),大端(Big-Endian),小端(Little-Endian)

    http://www.cppblog.com/tx7do/archive/2009/01/06/71276.html 在各种计算机体系结构中,对于字节.字等的存储机制有所不同,因而引发了计算机通信领域 ...

  9. gitlab发送邮件配置

    在使用gitlab过程中,通常需配置邮件来实现代码管理服务器向成员(member)发送邮件.本文将实现gitlab中邮件配置 1.编辑 /etc/gitlab/gitlab.rb,修改配置邮件,这里以 ...

  10. CodeForces 588E A Simple Task(线段树)

    This task is very simple. Given a string S of length n and q queries each query is on the format i j ...